diff --git a/ORACLE_LINUX_DEPLOYMENT.md b/ORACLE_LINUX_DEPLOYMENT.md new file mode 100644 index 0000000..df83285 --- /dev/null +++ b/ORACLE_LINUX_DEPLOYMENT.md @@ -0,0 +1,721 @@ +# OracleQuant API Deployment Guide + +This guide explains how to run **OracleQuant API** on **Oracle Linux VirtualBox** and connect it to an **Oracle Database Free Docker container running on Windows**. + +This setup is for a **local development / training deployment**, not public production hosting. + +--- + +## 1. Final Working Setup + +| Part | Machine | Value | +|---|---|---| +| Oracle Database | Windows Docker | `container-registry.oracle.com/database/free:latest` | +| Oracle DB Container Name | Windows | `oracle-db` | +| Oracle DB Port | Windows | `1521` | +| Oracle DB Service Name | Docker Oracle DB | `FREEPDB1` | +| Oracle DB Admin User | Docker Oracle DB | `SYSTEM` | +| Oracle DB Admin Password | Docker Oracle DB | `OracleAdmin7191` | +| App DB User | Oracle DB | `ORACLEQUANTAPI` | +| App DB Password | Oracle DB | `StrongPassword123` | +| Spring Boot JAR | Oracle Linux | `/home/sulaiman/oraclequantapi.jar` | +| API Port | Oracle Linux | `8080` | +| Windows IP | Windows Wi-Fi | `172.20.10.2` | +| Oracle Linux IP | VirtualBox Bridged Adapter | `172.20.10.3` | +| API Base URL | Browser/Postman | `http://172.20.10.3:8080` | + +> Important: Your IPs can change after restarting Wi-Fi, Windows hotspot, or the VM. Always check them again if something stops working. + +--- + +## 2. Where to Run Each Command + +| Command Type | Run It In | +|---|---| +| `docker ps`, `docker exec`, `docker logs` | Windows CMD | +| `netsh advfirewall ...` | Windows CMD as Administrator | +| `java -jar ...` | Oracle Linux terminal | +| `ip addr` | Oracle Linux terminal | +| `timeout 5 bash -c ...` | Oracle Linux terminal | +| SQL commands | Inside `SQL>` prompt | +| API testing | Windows browser or Postman | + +--- + +## 3. Start Oracle Database on Windows + +Open **Windows CMD**. + +Check Docker: + +```cmd +docker ps +``` + +If the container already exists but is stopped, start it: + +```cmd +docker start oracle-db +``` + +If the container does not exist, create it: + +```cmd +docker run -d --name oracle-db -p 1521:1521 -e ORACLE_PWD=OracleAdmin7191 container-registry.oracle.com/database/free:latest +``` + +Check that it is running: + +```cmd +docker ps +``` + +Expected: + +```text +oracle-db +0.0.0.0:1521->1521/tcp +healthy +``` + +Check logs: + +```cmd +docker logs -f oracle-db +``` + +Wait until the database is ready. When done, press: + +```text +CTRL + C +``` + +This only stops viewing logs. It does not stop the database. + +--- + +## 4. Test Oracle Database Inside Docker + +Run in **Windows CMD**: + +```cmd +docker exec -it oracle-db sqlplus system/OracleAdmin7191@localhost:1521/FREEPDB1 +``` + +If connected, you will see: + +```sql +SQL> +``` + +Exit: + +```sql +EXIT; +``` + +--- + +## 5. Open Windows Firewall Port 1521 + +Open **CMD as Administrator**. + +Run: + +```cmd +netsh advfirewall firewall add rule name="Oracle DB 1521" dir=in action=allow protocol=TCP localport=1521 +``` + +Expected: + +```text +Ok. +``` + +This allows Oracle Linux to reach the Oracle Database running on Windows Docker. + +--- + +## 6. Configure VirtualBox Network + +In **VirtualBox Manager**: + +1. Shut down Oracle Linux first: + +```bash +sudo poweroff +``` + +2. Select your Oracle Linux VM. +3. Go to: + +```text +Settings -> Network +``` + +4. Adapter 1: + +```text +Attached to: Bridged Adapter +Name: Intel(R) Dual Band Wireless-AC 3165 +Cable Connected: checked +``` + +5. Click **OK**. +6. Start Oracle Linux again. + +--- + +## 7. Check Oracle Linux IP + +Run inside **Oracle Linux**: + +```bash +ip addr +``` + +Look for `enp0s3`. + +Working example: + +```text +inet 172.20.10.3/28 +``` + +So your Linux API IP is: + +```text +172.20.10.3 +``` + +Your Windows IP from `ipconfig` is: + +```text +172.20.10.2 +``` + +Both must be on the same network: + +```text +Windows: 172.20.10.2 +Oracle Linux: 172.20.10.3 +``` + +--- + +## 8. Test Windows Oracle DB Port From Oracle Linux + +Run this in **Oracle Linux**: + +```bash +timeout 5 bash -c '` run: + +```sql +CREATE USER ORACLEQUANTAPI IDENTIFIED BY "StrongPassword123"; + +GRANT CREATE SESSION TO ORACLEQUANTAPI; +GRANT CREATE TABLE TO ORACLEQUANTAPI; +GRANT CREATE SEQUENCE TO ORACLEQUANTAPI; +GRANT CREATE VIEW TO ORACLEQUANTAPI; +GRANT UNLIMITED TABLESPACE TO ORACLEQUANTAPI; +``` + +If `CREATE USER` says the user already exists, continue with the grants. + +Exit: + +```sql +EXIT; +``` + +--- + +## 10. Create Application Table + +Connect as the app user: + +```cmd +docker exec -it oracle-db sqlplus ORACLEQUANTAPI/StrongPassword123@localhost:1521/FREEPDB1 +``` + +Create the table: + +```sql +CREATE TABLE sequence_history ( + id RAW(16) PRIMARY KEY, + timestamp TIMESTAMP, + input VARCHAR2(2000), + output VARCHAR2(2000) +); +``` + +If it says table already exists, that is okay. + +Check the table: + +```sql +SELECT table_name +FROM user_tables +WHERE table_name = 'SEQUENCE_HISTORY'; +``` + +Expected: + +```text +SEQUENCE_HISTORY +``` + +Exit: + +```sql +EXIT; +``` + +--- + +## 11. Copy JAR to Oracle Linux + +If the JAR is not already on Oracle Linux, copy it from **Windows CMD or PowerShell**: + +```cmd +scp "C:\Users\Codeline\Documents\GitHub\oraclequantapi\target\oraclequantapi-0.0.1.jar" sulaiman@172.20.10.3:/home/sulaiman/oraclequantapi.jar +``` + +Check on Oracle Linux: + +```bash +ls -lh /home/sulaiman/oraclequantapi.jar +``` + +--- + +## 12. Check Java 17 on Oracle Linux + +Run: + +```bash +java -version +``` + +If Java is missing: + +```bash +sudo dnf install -y java-17-openjdk +java -version +``` + +--- + +## 13. Run Spring Boot API Manually + +Run this in **Oracle Linux**: + +```bash +export SPRING_DATASOURCE_URL='jdbc:oracle:thin:@//172.20.10.2:1521/FREEPDB1' +export SPRING_DATASOURCE_USERNAME='ORACLEQUANTAPI' +export SPRING_DATASOURCE_PASSWORD='StrongPassword123' +export SPRING_DATASOURCE_DRIVER_CLASS_NAME='oracle.jdbc.OracleDriver' +export SPRING_JPA_HIBERNATE_DDL_AUTO='validate' +export SPRING_JPA_OPEN_IN_VIEW='false' + +java -jar /home/sulaiman/oraclequantapi.jar --server.address=0.0.0.0 --server.port=8080 +``` + +Successful startup should include something like: + +```text +HikariPool-1 - Added connection +Tomcat started on port 8080 +Started PackageMeasurementApiApplication +``` + +Keep this terminal open while testing. + +--- + +## 14. Open Oracle Linux Firewall Port 8080 + +In another Oracle Linux terminal: + +```bash +sudo firewall-cmd --permanent --add-port=8080/tcp +sudo firewall-cmd --reload +sudo firewall-cmd --list-ports +``` + +--- + +## 15. Test API From Windows + +Open browser or Postman on Windows. + +Base URL: + +```text +http://172.20.10.3:8080 +``` + +Test history: + +```text +http://172.20.10.3:8080/history +``` + +Test conversion: + +```text +http://172.20.10.3:8080/convert-measurements?input=1kg +``` + +--- + +## 16. Check Saved Data in Oracle Database + +Run in **Windows CMD**: + +```cmd +docker exec -it oracle-db sqlplus ORACLEQUANTAPI/StrongPassword123@localhost:1521/FREEPDB1 +``` + +Inside `SQL>`: + +```sql +SELECT * FROM sequence_history ORDER BY timestamp DESC; +``` + +Exit: + +```sql +EXIT; +``` + +--- + +## 17. Run API in Background Temporarily + +For quick background testing on Oracle Linux: + +```bash +nohup java -jar /home/sulaiman/oraclequantapi.jar --server.address=0.0.0.0 --server.port=8080 > /home/sulaiman/oraclequantapi.log 2>&1 & +``` + +Check logs: + +```bash +tail -f /home/sulaiman/oraclequantapi.log +``` + +Stop it: + +```bash +pkill -f oraclequantapi.jar +``` + +--- + +## 18. Run API as a systemd Service + +Create environment file: + +```bash +sudo vi /etc/oraclequantapi.env +``` + +Paste: + +```bash +SPRING_DATASOURCE_URL=jdbc:oracle:thin:@//172.20.10.2:1521/FREEPDB1 +SPRING_DATASOURCE_USERNAME=ORACLEQUANTAPI +SPRING_DATASOURCE_PASSWORD=StrongPassword123 +SPRING_DATASOURCE_DRIVER_CLASS_NAME=oracle.jdbc.OracleDriver +SPRING_JPA_HIBERNATE_DDL_AUTO=validate +SPRING_JPA_OPEN_IN_VIEW=false +``` + +Protect it: + +```bash +sudo chmod 600 /etc/oraclequantapi.env +``` + +Create service file: + +```bash +sudo vi /etc/systemd/system/oraclequantapi.service +``` + +Paste: + +```ini +[Unit] +Description=Oracle Quant API +After=network.target + +[Service] +User=sulaiman +WorkingDirectory=/home/sulaiman +EnvironmentFile=/etc/oraclequantapi.env +ExecStart=/usr/bin/java -jar /home/sulaiman/oraclequantapi.jar --server.address=0.0.0.0 --server.port=8080 +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +``` + +Start service: + +```bash +sudo systemctl daemon-reload +sudo systemctl start oraclequantapi +sudo systemctl enable oraclequantapi +``` + +Check status: + +```bash +sudo systemctl status oraclequantapi +``` + +View logs: + +```bash +journalctl -u oraclequantapi -f +``` + +Restart after replacing JAR: + +```bash +sudo systemctl restart oraclequantapi +``` + +Stop service: + +```bash +sudo systemctl stop oraclequantapi +``` + +--- + +## 19. Daily Start Checklist + +### On Windows + +Start Docker Desktop. + +Check Oracle DB: + +```cmd +docker ps +``` + +If stopped: + +```cmd +docker start oracle-db +``` + +### On Oracle Linux + +Check IP: + +```bash +ip addr +``` + +Test DB port: + +```bash +timeout 5 bash -c ' +``` + +Not from: + +```text +[sulaiman@localhost ~]$ +``` + +--- + +### Error: `NoRouteToHostException` + +Linux cannot reach Windows DB port. + +Fix: + +1. Use Bridged Adapter in VirtualBox. +2. Make sure Windows and Linux are on same network. +3. Open Windows firewall port `1521`. +4. Test: + +```bash +timeout 5 bash -c ' com.oraclequantapi oraclequantapi - 0.0.1-SNAPSHOT + 0.0.1 @@ -35,6 +35,23 @@ spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + runtime + + + + com.oracle.database.jdbc + ojdbc11 + runtime + + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/com/example/pkc_api/PackageMeasurementApiApplication.java b/src/main/java/com/example/pkc_api/PackageMeasurementApiApplication.java new file mode 100644 index 0000000..acc1c39 --- /dev/null +++ b/src/main/java/com/example/pkc_api/PackageMeasurementApiApplication.java @@ -0,0 +1,12 @@ +package com.example.pkc_api; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PackageMeasurementApiApplication { + + public static void main(String[] args) { + SpringApplication.run(PackageMeasurementApiApplication.class, args); + } +} diff --git a/src/main/java/com/example/pkc_api/config/CorsConfig.java b/src/main/java/com/example/pkc_api/config/CorsConfig.java new file mode 100644 index 0000000..c98cfb0 --- /dev/null +++ b/src/main/java/com/example/pkc_api/config/CorsConfig.java @@ -0,0 +1,17 @@ +package com.example.pkc_api.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class CorsConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") // TODO: Restrict this for production. + .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") + .allowedHeaders("*"); + } +} diff --git a/src/main/java/com/example/pkc_api/controller/HistoryController.java b/src/main/java/com/example/pkc_api/controller/HistoryController.java new file mode 100644 index 0000000..bd202f8 --- /dev/null +++ b/src/main/java/com/example/pkc_api/controller/HistoryController.java @@ -0,0 +1,53 @@ +package com.example.pkc_api.controller; + + +import com.example.pkc_api.dto.UpdateHistoryRequest; +import com.example.pkc_api.entity.SequenceHistory; +import com.example.pkc_api.service.HistoryService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/history") +public class HistoryController { + + private final HistoryService historyService; + + public HistoryController(HistoryService historyService) { + this.historyService = historyService; + } + + @GetMapping + public List getAllHistory() { + return historyService.getAllHistory(); + } + + @GetMapping("/{id}") + public SequenceHistory getHistoryById(@PathVariable UUID id) { + return historyService.getHistoryById(id); + } + + @PatchMapping("/{id}") + public SequenceHistory updateHistory( + @PathVariable UUID id, + @RequestBody UpdateHistoryRequest request + ) { + return historyService.updateHistory(id, request); + } + + @PutMapping("/{id}") + public SequenceHistory replaceHistory( + @PathVariable UUID id, + @RequestBody UpdateHistoryRequest request + ) { + return historyService.updateHistory(id, request); + } + + @DeleteMapping + public String clearHistory() { + historyService.clearHistory(); + return "History cleared successfully."; + } +} diff --git a/src/main/java/com/example/pkc_api/controller/MeasurementController.java b/src/main/java/com/example/pkc_api/controller/MeasurementController.java new file mode 100644 index 0000000..fce1af6 --- /dev/null +++ b/src/main/java/com/example/pkc_api/controller/MeasurementController.java @@ -0,0 +1,38 @@ +package com.example.pkc_api.controller; + + +import com.example.pkc_api.service.HistoryService; +import com.example.pkc_api.service.MeasurementConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +public class MeasurementController { + + private static final Logger log = LoggerFactory.getLogger(MeasurementController.class); + + private final MeasurementConverter measurementConverter; + private final HistoryService historyService; + + public MeasurementController(MeasurementConverter measurementConverter, HistoryService historyService) { + this.measurementConverter = measurementConverter; + this.historyService = historyService; + } + + @GetMapping("/convert-measurements") + public List convertMeasurements( + @RequestParam String input + ) { + List output = measurementConverter.convertMeasurements(input); + + historyService.saveHistory(input, output.toString()); + log.info("Converted measurement inputLength={} output={}", input.length(), output); + + return output; + } +} diff --git a/src/main/java/com/example/pkc_api/dto/UpdateHistoryRequest.java b/src/main/java/com/example/pkc_api/dto/UpdateHistoryRequest.java new file mode 100644 index 0000000..b9f4c51 --- /dev/null +++ b/src/main/java/com/example/pkc_api/dto/UpdateHistoryRequest.java @@ -0,0 +1,23 @@ +package com.example.pkc_api.dto; + +public class UpdateHistoryRequest { + + private String input; + private String output; + + public String getInput() { + return input; + } + + public String getOutput() { + return output; + } + + public void setInput(String input) { + this.input = input; + } + + public void setOutput(String output) { + this.output = output; + } +} diff --git a/src/main/java/com/example/pkc_api/entity/SequenceHistory.java b/src/main/java/com/example/pkc_api/entity/SequenceHistory.java new file mode 100644 index 0000000..014735b --- /dev/null +++ b/src/main/java/com/example/pkc_api/entity/SequenceHistory.java @@ -0,0 +1,65 @@ +package com.example.pkc_api.entity; + + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Entity +@Table(name = "sequence_history") +@SuppressWarnings("unused") +public class SequenceHistory { + + @Id + @Column(nullable = false, updatable = false) + private UUID id = UUID.randomUUID(); + + private LocalDateTime timestamp; + + @Column(length = 2000) + private String input; + + @Column(length = 2000) + private String output; + + public SequenceHistory() { + } + + public SequenceHistory(LocalDateTime timestamp, String input, String output) { + this.timestamp = timestamp; + this.input = input; + this.output = output; + } + + public UUID getId() { + return id; + } + + public LocalDateTime getTimestamp() { + return timestamp; + } + + public String getInput() { + return input; + } + + public String getOutput() { + return output; + } + + public void setTimestamp(LocalDateTime timestamp) { + this.timestamp = timestamp; + } + + public void setInput(String input) { + this.input = input; + } + + public void setOutput(String output) { + this.output = output; + } +} diff --git a/src/main/java/com/example/pkc_api/exception/HistoryRecordNotFoundException.java b/src/main/java/com/example/pkc_api/exception/HistoryRecordNotFoundException.java new file mode 100644 index 0000000..899dbbe --- /dev/null +++ b/src/main/java/com/example/pkc_api/exception/HistoryRecordNotFoundException.java @@ -0,0 +1,14 @@ +package com.example.pkc_api.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +import java.util.UUID; + +@ResponseStatus(HttpStatus.NOT_FOUND) +public class HistoryRecordNotFoundException extends RuntimeException { + + public HistoryRecordNotFoundException(UUID id) { + super("History record not found with id: " + id); + } +} diff --git a/src/main/java/com/example/pkc_api/parser/EncodedNumberParser.java b/src/main/java/com/example/pkc_api/parser/EncodedNumberParser.java new file mode 100644 index 0000000..f3ffbf8 --- /dev/null +++ b/src/main/java/com/example/pkc_api/parser/EncodedNumberParser.java @@ -0,0 +1,53 @@ +package com.example.pkc_api.parser; + +import org.springframework.stereotype.Component; + +@Component +public class EncodedNumberParser implements NumberParser { + + @Override + public ParsedNumber parse(String input, int startIndex) { + if (input == null || startIndex >= input.length()) { + return new ParsedNumber(0, startIndex); + } + + char current = input.charAt(startIndex); + + if (isContinuationCharacter(current)) { + return parseMultiCharacterNumber(input, startIndex); + } + + int value = getCharacterValue(current); + return new ParsedNumber(value, startIndex + 1); + } + + private ParsedNumber parseMultiCharacterNumber(String input, int index) { + int total = 0; + + while (index < input.length() && isContinuationCharacter(input.charAt(index))) { + total += 26; + index++; + } + + if (index < input.length()) { + total += getCharacterValue(input.charAt(index)); + index++; + } + + return new ParsedNumber(total, index); + } + + private int getCharacterValue(char character) { + character = Character.toLowerCase(character); + + if (character >= 'a' && character <= 'z') { + return character - 'a' + 1; + } + + return 0; + } + + private boolean isContinuationCharacter(char character) { + return Character.toLowerCase(character) == 'z'; + } +} diff --git a/src/main/java/com/example/pkc_api/parser/NumberParser.java b/src/main/java/com/example/pkc_api/parser/NumberParser.java new file mode 100644 index 0000000..451a6e0 --- /dev/null +++ b/src/main/java/com/example/pkc_api/parser/NumberParser.java @@ -0,0 +1,6 @@ +package com.example.pkc_api.parser; + +public interface NumberParser { + + ParsedNumber parse(String input, int startIndex); +} diff --git a/src/main/java/com/example/pkc_api/parser/ParsedNumber.java b/src/main/java/com/example/pkc_api/parser/ParsedNumber.java new file mode 100644 index 0000000..75e96a1 --- /dev/null +++ b/src/main/java/com/example/pkc_api/parser/ParsedNumber.java @@ -0,0 +1,20 @@ +package com.example.pkc_api.parser; + +public class ParsedNumber { + + private final int value; + private final int nextIndex; + + public ParsedNumber(int value, int nextIndex) { + this.value = value; + this.nextIndex = nextIndex; + } + + public int getValue() { + return value; + } + + public int getNextIndex() { + return nextIndex; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/pkc_api/repository/SequenceHistoryRepository.java b/src/main/java/com/example/pkc_api/repository/SequenceHistoryRepository.java new file mode 100644 index 0000000..11292b0 --- /dev/null +++ b/src/main/java/com/example/pkc_api/repository/SequenceHistoryRepository.java @@ -0,0 +1,10 @@ +package com.example.pkc_api.repository; + + +import com.example.pkc_api.entity.SequenceHistory; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface SequenceHistoryRepository extends JpaRepository { +} diff --git a/src/main/java/com/example/pkc_api/service/HistoryService.java b/src/main/java/com/example/pkc_api/service/HistoryService.java new file mode 100644 index 0000000..f1a0a68 --- /dev/null +++ b/src/main/java/com/example/pkc_api/service/HistoryService.java @@ -0,0 +1,69 @@ +package com.example.pkc_api.service; + + +import com.example.pkc_api.dto.UpdateHistoryRequest; +import com.example.pkc_api.entity.SequenceHistory; +import com.example.pkc_api.exception.HistoryRecordNotFoundException; +import com.example.pkc_api.repository.SequenceHistoryRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; + +@Service +public class HistoryService { + + private static final Logger log = LoggerFactory.getLogger(HistoryService.class); + + private final SequenceHistoryRepository historyRepository; + + public HistoryService(SequenceHistoryRepository historyRepository) { + this.historyRepository = historyRepository; + } + + public SequenceHistory saveHistory(String input, String output) { + SequenceHistory history = new SequenceHistory( + LocalDateTime.now(), + input, + output + ); + + SequenceHistory savedHistory = historyRepository.save(history); + log.info("Saved history record id={}", savedHistory.getId()); + return savedHistory; + } + + public List getAllHistory() { + return historyRepository.findAll(Sort.by(Sort.Direction.ASC, "id")); + } + + public SequenceHistory getHistoryById(UUID id) { + return historyRepository.findById(id) + .orElseThrow(() -> new HistoryRecordNotFoundException(id)); + } + + public SequenceHistory updateHistory(UUID id, UpdateHistoryRequest request) { + SequenceHistory history = getHistoryById(id); + + if (request.getInput() != null) { + history.setInput(request.getInput()); + } + + if (request.getOutput() != null) { + history.setOutput(request.getOutput()); + } + + SequenceHistory savedHistory = historyRepository.save(history); + log.info("Updated history record id={}", id); + return savedHistory; + } + + public void clearHistory() { + historyRepository.deleteAll(); + log.info("Cleared all history records"); + } +} diff --git a/src/main/java/com/example/pkc_api/service/MeasurementConverter.java b/src/main/java/com/example/pkc_api/service/MeasurementConverter.java new file mode 100644 index 0000000..1a0f37b --- /dev/null +++ b/src/main/java/com/example/pkc_api/service/MeasurementConverter.java @@ -0,0 +1,8 @@ +package com.example.pkc_api.service; + +import java.util.List; + +public interface MeasurementConverter { + + List convertMeasurements(String input); +} diff --git a/src/main/java/com/example/pkc_api/service/SequenceService.java b/src/main/java/com/example/pkc_api/service/SequenceService.java new file mode 100644 index 0000000..74f3657 --- /dev/null +++ b/src/main/java/com/example/pkc_api/service/SequenceService.java @@ -0,0 +1,54 @@ +package com.example.pkc_api.service; + + +import com.example.pkc_api.parser.NumberParser; +import com.example.pkc_api.parser.ParsedNumber; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class SequenceService implements MeasurementConverter { + + private final NumberParser numberParser; + + public SequenceService(NumberParser numberParser) { + this.numberParser = numberParser; + } + + @Override + public List convertMeasurements(String input) { + List result = new ArrayList<>(); + + if (input == null || input.isEmpty()) { + return result; + } + + int index = 0; + + while (index < input.length()) { + ParsedNumber countNumber = numberParser.parse(input, index); + + int count = countNumber.getValue(); + index = countNumber.getNextIndex(); + + int packageTotal = 0; + + for (int i = 0; i < count; i++) { + if (index >= input.length()) { + break; + } + + ParsedNumber measurementNumber = numberParser.parse(input, index); + + packageTotal += measurementNumber.getValue(); + index = measurementNumber.getNextIndex(); + } + + result.add(packageTotal); + } + + return result; + } +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java b/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java deleted file mode 100644 index 5e28689..0000000 --- a/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.oraclequantapi.oraclequantapi; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class OraclequantapiApplication { - - public static void main(String[] args) { - SpringApplication.run(OraclequantapiApplication.class, args); - } - -} diff --git a/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java b/src/test/java/com/example/pkc_api/OraclequantapiApplicationTests.java similarity index 81% rename from src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java rename to src/test/java/com/example/pkc_api/OraclequantapiApplicationTests.java index 2de285b..a991606 100644 --- a/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java +++ b/src/test/java/com/example/pkc_api/OraclequantapiApplicationTests.java @@ -1,4 +1,4 @@ -package com.oraclequantapi.oraclequantapi; +package com.example.pkc_api; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest;