diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b3209d3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +## [1.0.0] - 2026-05-24 + +### Added +- GET /convert-measurements endpoint +- History CRUD endpoints (GET, PUT, PATCH, DELETE) +- Oracle XE Database integration +- Rolling log files (7 days) +- README.md documentation +- Deployed on Oracle Linux via WSL +- SSH Access enabled \ No newline at end of file diff --git a/README.md b/README.md index b1cccfd..83bea40 100644 --- a/README.md +++ b/README.md @@ -59,3 +59,198 @@ To submit your Oracle JAVA Spring Boot Maven project as a solution, please follo ## Note: If you face any issues in the process above, Please do the following: - Watch [this youtube tutorial](https://www.youtube.com/watch?v=a_FLqX3vGR4) - Contact Ikhlas or Atyab. +----------------# OracleQuant API - Package Measurement Conversion + +## How to Build +```bash +cd oraclequantapi +mvn clean package -DskipTests +``` + +## How to Run +```bash +java -jar target/oraclequantapi-0.0.1-SNAPSHOT.jar +``` + +## Database Configuration +Make sure Oracle XE is running via Docker: +```bash +docker run -d --name oracle-xe -p 1521:1521 -e ORACLE_PASSWORD=29999login gvenzl/oracle-xe:21-slim +``` + +Update `application.properties`: + +# OracleQuant ERP - Package Measurement Conversion API + +## Overview +A REST API for converting package measurement input strings into a list of total values per package. Built with Java 17, Spring Boot, and Oracle XE Database. + +--- + +## Prerequisites +- Oracle OpenJDK 17 +- Oracle XE Database +- Maven 3.x + +--- + +## Building the Application + +```bash +./mvnw clean package +``` + +The JAR file will be generated at: +``` +target/oraclequantapi-0.0.1-SNAPSHOT.jar +``` + +--- + +## Configuring the Database + +Edit `src/main/resources/application.properties`: + +```properties +spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE +spring.datasource.username=system +spring.datasource.password=YOUR_PASSWORD +spring.datasource.driver-class-name=oracle.jdbc.OracleDriver +spring.jpa.hibernate.ddl-auto=update +``` + +--- + +## Running the Application + +### On Windows: +```bash +./mvnw spring-boot:run +``` + +### On Oracle Linux: +```bash +java -jar oraclequantapi-0.0.1-SNAPSHOT.jar +``` + +The application runs on port **8080** by default. + +--- + +## Deploying on Oracle Linux via SSH + +### Step 1 — Copy JAR to Oracle Linux server: +```bash +scp -P 22 target/oraclequantapi-0.0.1-SNAPSHOT.jar user@SERVER_IP:/home/user/ +``` + +### Step 2 — SSH into the server: +```bash +ssh user@SERVER_IP +``` + +### Step 3 — Run the application: +```bash +java -jar /home/user/oraclequantapi-0.0.1-SNAPSHOT.jar +``` + +### Step 4 — Run in background (keep running after logout): +```bash +nohup java -jar /home/user/oraclequantapi-0.0.1-SNAPSHOT.jar > /dev/null 2>&1 & +``` + +--- + +## REST API Endpoints + +### Conversion Endpoint + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/convert-measurements?input={string}` | Convert measurement input string | + +**Example:** +``` +GET http://localhost:8080/convert-measurements?input=abbcc +Response: [2, 6] +``` + +--- + +### History Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/history` | Get all history records | +| GET | `/history/{id}` | Get record by ID | +| PUT | `/history/{id}` | Update record by ID | +| PATCH | `/history/{id}` | Partially update record by ID | +| DELETE | `/history` | Delete all history records | + +**Example:** +``` +GET http://localhost:8080/history +Response: +[ + { + "id": 1, + "timestamp": "2026-05-24T00:48:17", + "sourceIpAddress": "0:0:0:0:0:0:0:1", + "input": "abbcc", + "output": "[2, 6]" + } +] +``` + +--- + +## Input Encoding Format + +- Letters `a–y` map to values `1–25` +- Letter `z` means continue reading (add next character too) +- `_` means `0` +- First character = count of values in the package +- Remaining characters = the values + +**Examples:** + +| Input | Output | +|-------|--------| +| `aa` | `[1]` | +| `abbcc` | `[2, 6]` | +| `dz_a_aazzaaa` | `[28, 53, 1]` | +| `a_` | `[0]` | + +--- + +## Logging + +Logs are written to: +``` +logs/pkc-api.log +``` +- Rolling logs: 7 days history +- Log level: INFO + +--- + +## Project Structure + +``` +src/ +├── main/ +│ ├── java/com/oraclequantapi/oraclequantapi/ +│ │ ├── controller/ +│ │ │ ├── ConversionController.java +│ │ │ └── HistoryController.java +│ │ ├── model/ +│ │ │ └── ConversionHistory.java +│ │ ├── repository/ +│ │ │ └── HistoryRepository.java +│ │ ├── service/ +│ │ │ ├── ConversionService.java +│ │ │ └── HistoryService.java +│ │ └── OraclequantapiApplication.java +│ └── resources/ +│ └── application.properties +``` diff --git a/logs/pkc-api.log b/logs/pkc-api.log new file mode 100644 index 0000000..b7ce2ab --- /dev/null +++ b/logs/pkc-api.log @@ -0,0 +1,108 @@ +2026-05-24T00:06:11.650+04:00 INFO 25884 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : Starting OraclequantapiApplicationTests using Java 17.0.19 with PID 25884 (started by PC in C:\Users\PC\Desktop\kawther3lii-evaluation4\oraclequantapi) +2026-05-24T00:06:11.658+04:00 INFO 25884 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : No active profile set, falling back to 1 default profile: "default" +2026-05-24T00:06:12.317+04:00 INFO 25884 --- [oraclequantapi] [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2026-05-24T00:06:12.379+04:00 INFO 25884 --- [oraclequantapi] [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 52 ms. Found 1 JPA repository interface. +2026-05-24T00:06:12.875+04:00 INFO 25884 --- [oraclequantapi] [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] +2026-05-24T00:06:12.955+04:00 INFO 25884 --- [oraclequantapi] [main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.6.15.Final +2026-05-24T00:06:12.996+04:00 INFO 25884 --- [oraclequantapi] [main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled +2026-05-24T00:06:13.350+04:00 INFO 25884 --- [oraclequantapi] [main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer +2026-05-24T00:06:13.385+04:00 INFO 25884 --- [oraclequantapi] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... +2026-05-24T00:06:13.750+04:00 INFO 25884 --- [oraclequantapi] [main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection oracle.jdbc.driver.T4CConnection@e07b4db +2026-05-24T00:06:13.751+04:00 INFO 25884 --- [oraclequantapi] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. +2026-05-24T00:06:13.889+04:00 WARN 25884 --- [oraclequantapi] [main] org.hibernate.orm.deprecation : HHH90000025: OracleDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) +2026-05-24T00:06:14.009+04:00 INFO 25884 --- [oraclequantapi] [main] org.hibernate.orm.connections.pooling : HHH10001005: Database info: + Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)'] + Database driver: undefined/unknown + Database version: 21.3 + Autocommit mode: undefined/unknown + Isolation level: undefined/unknown + Minimum pool size: undefined/unknown + Maximum pool size: undefined/unknown +2026-05-24T00:06:14.746+04:00 INFO 25884 --- [oraclequantapi] [main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) +2026-05-24T00:06:16.306+04:00 INFO 25884 --- [oraclequantapi] [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' +2026-05-24T00:06:16.637+04:00 WARN 25884 --- [oraclequantapi] [main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +2026-05-24T00:06:17.015+04:00 INFO 25884 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : Started OraclequantapiApplicationTests in 5.705 seconds (process running for 6.596) +2026-05-24T00:06:17.415+04:00 INFO 25884 --- [oraclequantapi] [SpringApplicationShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' +2026-05-24T00:06:17.417+04:00 INFO 25884 --- [oraclequantapi] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... +2026-05-24T00:06:17.439+04:00 INFO 25884 --- [oraclequantapi] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. +2026-05-24T00:19:25.165+04:00 INFO 27364 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : Starting OraclequantapiApplicationTests using Java 17.0.19 with PID 27364 (started by PC in C:\Users\PC\Desktop\kawther3lii-evaluation4\oraclequantapi) +2026-05-24T00:19:25.168+04:00 INFO 27364 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : No active profile set, falling back to 1 default profile: "default" +2026-05-24T00:19:25.822+04:00 INFO 27364 --- [oraclequantapi] [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2026-05-24T00:19:25.889+04:00 INFO 27364 --- [oraclequantapi] [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 57 ms. Found 1 JPA repository interface. +2026-05-24T00:19:26.382+04:00 INFO 27364 --- [oraclequantapi] [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] +2026-05-24T00:19:26.446+04:00 INFO 27364 --- [oraclequantapi] [main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.6.15.Final +2026-05-24T00:19:26.483+04:00 INFO 27364 --- [oraclequantapi] [main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled +2026-05-24T00:19:26.811+04:00 INFO 27364 --- [oraclequantapi] [main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer +2026-05-24T00:19:26.846+04:00 INFO 27364 --- [oraclequantapi] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... +2026-05-24T00:19:27.175+04:00 INFO 27364 --- [oraclequantapi] [main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection oracle.jdbc.driver.T4CConnection@3193e21d +2026-05-24T00:19:27.177+04:00 INFO 27364 --- [oraclequantapi] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. +2026-05-24T00:19:27.312+04:00 WARN 27364 --- [oraclequantapi] [main] org.hibernate.orm.deprecation : HHH90000025: OracleDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) +2026-05-24T00:19:27.406+04:00 INFO 27364 --- [oraclequantapi] [main] org.hibernate.orm.connections.pooling : HHH10001005: Database info: + Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)'] + Database driver: undefined/unknown + Database version: 21.3 + Autocommit mode: undefined/unknown + Isolation level: undefined/unknown + Minimum pool size: undefined/unknown + Maximum pool size: undefined/unknown +2026-05-24T00:19:28.075+04:00 INFO 27364 --- [oraclequantapi] [main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) +2026-05-24T00:19:29.291+04:00 INFO 27364 --- [oraclequantapi] [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' +2026-05-24T00:19:29.652+04:00 WARN 27364 --- [oraclequantapi] [main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +2026-05-24T00:19:30.065+04:00 INFO 27364 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : Started OraclequantapiApplicationTests in 5.22 seconds (process running for 6.064) +2026-05-24T00:19:30.465+04:00 INFO 27364 --- [oraclequantapi] [SpringApplicationShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' +2026-05-24T00:19:30.468+04:00 INFO 27364 --- [oraclequantapi] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... +2026-05-24T00:19:30.491+04:00 INFO 27364 --- [oraclequantapi] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. +2026-05-24T00:34:04.204+04:00 INFO 3460 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : Starting OraclequantapiApplicationTests using Java 17.0.19 with PID 3460 (started by PC in C:\Users\PC\Desktop\kawther3lii-evaluation4\oraclequantapi) +2026-05-24T00:34:04.207+04:00 INFO 3460 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : No active profile set, falling back to 1 default profile: "default" +2026-05-24T00:34:04.851+04:00 INFO 3460 --- [oraclequantapi] [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2026-05-24T00:34:04.917+04:00 INFO 3460 --- [oraclequantapi] [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 55 ms. Found 1 JPA repository interface. +2026-05-24T00:34:05.350+04:00 INFO 3460 --- [oraclequantapi] [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] +2026-05-24T00:34:05.403+04:00 INFO 3460 --- [oraclequantapi] [main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.6.15.Final +2026-05-24T00:34:05.434+04:00 INFO 3460 --- [oraclequantapi] [main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled +2026-05-24T00:34:05.744+04:00 INFO 3460 --- [oraclequantapi] [main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer +2026-05-24T00:34:05.772+04:00 INFO 3460 --- [oraclequantapi] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... +2026-05-24T00:34:06.094+04:00 INFO 3460 --- [oraclequantapi] [main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection oracle.jdbc.driver.T4CConnection@63553e9f +2026-05-24T00:34:06.096+04:00 INFO 3460 --- [oraclequantapi] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. +2026-05-24T00:34:06.197+04:00 WARN 3460 --- [oraclequantapi] [main] org.hibernate.orm.deprecation : HHH90000025: OracleDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) +2026-05-24T00:34:06.285+04:00 INFO 3460 --- [oraclequantapi] [main] org.hibernate.orm.connections.pooling : HHH10001005: Database info: + Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)'] + Database driver: undefined/unknown + Database version: 21.3 + Autocommit mode: undefined/unknown + Isolation level: undefined/unknown + Minimum pool size: undefined/unknown + Maximum pool size: undefined/unknown +2026-05-24T00:34:06.940+04:00 INFO 3460 --- [oraclequantapi] [main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) +2026-05-24T00:34:07.979+04:00 INFO 3460 --- [oraclequantapi] [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' +2026-05-24T00:34:08.313+04:00 WARN 3460 --- [oraclequantapi] [main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +2026-05-24T00:34:08.691+04:00 INFO 3460 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : Started OraclequantapiApplicationTests in 4.831 seconds (process running for 5.667) +2026-05-24T00:34:09.076+04:00 INFO 3460 --- [oraclequantapi] [SpringApplicationShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' +2026-05-24T00:34:09.081+04:00 INFO 3460 --- [oraclequantapi] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... +2026-05-24T00:34:09.104+04:00 INFO 3460 --- [oraclequantapi] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. +2026-05-24T00:47:41.990+04:00 INFO 17060 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : Starting OraclequantapiApplicationTests using Java 17.0.19 with PID 17060 (started by PC in C:\Users\PC\Desktop\kawther3lii-evaluation4\oraclequantapi) +2026-05-24T00:47:41.993+04:00 INFO 17060 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : No active profile set, falling back to 1 default profile: "default" +2026-05-24T00:47:42.647+04:00 INFO 17060 --- [oraclequantapi] [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2026-05-24T00:47:42.703+04:00 INFO 17060 --- [oraclequantapi] [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 45 ms. Found 1 JPA repository interface. +2026-05-24T00:47:43.160+04:00 INFO 17060 --- [oraclequantapi] [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] +2026-05-24T00:47:43.218+04:00 INFO 17060 --- [oraclequantapi] [main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.6.15.Final +2026-05-24T00:47:43.252+04:00 INFO 17060 --- [oraclequantapi] [main] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled +2026-05-24T00:47:43.538+04:00 INFO 17060 --- [oraclequantapi] [main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer +2026-05-24T00:47:43.567+04:00 INFO 17060 --- [oraclequantapi] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... +2026-05-24T00:47:43.892+04:00 INFO 17060 --- [oraclequantapi] [main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection oracle.jdbc.driver.T4CConnection@243c4346 +2026-05-24T00:47:43.893+04:00 INFO 17060 --- [oraclequantapi] [main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. +2026-05-24T00:47:44.013+04:00 WARN 17060 --- [oraclequantapi] [main] org.hibernate.orm.deprecation : HHH90000025: OracleDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) +2026-05-24T00:47:44.097+04:00 INFO 17060 --- [oraclequantapi] [main] org.hibernate.orm.connections.pooling : HHH10001005: Database info: + Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)'] + Database driver: undefined/unknown + Database version: 21.3 + Autocommit mode: undefined/unknown + Isolation level: undefined/unknown + Minimum pool size: undefined/unknown + Maximum pool size: undefined/unknown +2026-05-24T00:47:44.736+04:00 INFO 17060 --- [oraclequantapi] [main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) +2026-05-24T00:47:45.814+04:00 INFO 17060 --- [oraclequantapi] [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' +2026-05-24T00:47:46.137+04:00 WARN 17060 --- [oraclequantapi] [main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +2026-05-24T00:47:46.507+04:00 INFO 17060 --- [oraclequantapi] [main] c.o.o.OraclequantapiApplicationTests : Started OraclequantapiApplicationTests in 4.877 seconds (process running for 5.744) +2026-05-24T00:47:46.870+04:00 INFO 17060 --- [oraclequantapi] [SpringApplicationShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' +2026-05-24T00:47:46.873+04:00 INFO 17060 --- [oraclequantapi] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... +2026-05-24T00:47:46.893+04:00 INFO 17060 --- [oraclequantapi] [SpringApplicationShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. diff --git a/logs/pkc-api.log.2026-05-23.0.gz b/logs/pkc-api.log.2026-05-23.0.gz new file mode 100644 index 0000000..f413fa7 Binary files /dev/null and b/logs/pkc-api.log.2026-05-23.0.gz differ diff --git a/pom.xml b/pom.xml index 20909d2..dcf58a7 100644 --- a/pom.xml +++ b/pom.xml @@ -1,45 +1,52 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework.boot spring-boot-starter-parent - 3.5.14 - + 3.5.0 + + com.oraclequantapi oraclequantapi 0.0.1-SNAPSHOT - - - - - - - - - - - - - - - + oraclequantapi + Package Measurement Conversion API + 17 + + + org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + com.oracle.database.jdbc + ojdbc11 + 23.4.0.24.05 + + + org.springframework.boot spring-boot-starter-test test + diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/controller/ConversionController.java b/src/main/java/com/oraclequantapi/oraclequantapi/controller/ConversionController.java new file mode 100644 index 0000000..c30b681 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/controller/ConversionController.java @@ -0,0 +1,58 @@ +package com.oraclequantapi.oraclequantapi.controller; + +import com.oraclequantapi.oraclequantapi.model.ConversionHistory; +import com.oraclequantapi.oraclequantapi.service.ConversionService; +import com.oraclequantapi.oraclequantapi.service.HistoryService; +import jakarta.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.time.LocalDateTime; +import java.util.List; + +// This controller handles the main conversion endpoint +@RestController +public class ConversionController { + + // Logger for tracking requests and results + private static final Logger logger = LoggerFactory.getLogger(ConversionController.class); + + private final ConversionService conversionService; + private final HistoryService historyService; + + // Inject both services via constructor + public ConversionController(ConversionService conversionService, + HistoryService historyService) { + this.conversionService = conversionService; + this.historyService = historyService; + } + + // GET /convert-measurements?input=... + // Accepts an encoded input string and returns a list of package totals + @GetMapping("/convert-measurements") + public ResponseEntity> convert( + @RequestParam("input") String input, + HttpServletRequest request) { + + logger.info("Received conversion request with input: {}", input); + + // Run the conversion algorithm + List result = conversionService.convert(input); + + // Build a history record to persist this request + ConversionHistory record = new ConversionHistory(); + record.setTimestamp(LocalDateTime.now()); // current time + record.setSourceIpAddress(request.getRemoteAddr()); // client IP + record.setInput(input); // original input + record.setOutput(result.toString()); // result as string + + // Save the record to the database + historyService.save(record); + + logger.info("Conversion result: {}", result); + + // Return 200 OK with the result list + return ResponseEntity.ok(result); + } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/controller/HistoryController.java b/src/main/java/com/oraclequantapi/oraclequantapi/controller/HistoryController.java new file mode 100644 index 0000000..a16b6cb --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/controller/HistoryController.java @@ -0,0 +1,70 @@ +package com.oraclequantapi.oraclequantapi.controller; + +import com.oraclequantapi.oraclequantapi.model.ConversionHistory; +import com.oraclequantapi.oraclequantapi.service.HistoryService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.List; + +// This controller exposes CRUD endpoints for conversion history +@RestController +@RequestMapping("/history") +public class HistoryController { + + private static final Logger logger = LoggerFactory.getLogger(HistoryController.class); + + private final HistoryService historyService; + + // Inject HistoryService via constructor + public HistoryController(HistoryService historyService) { + this.historyService = historyService; + } + + // GET /history — returns all history records + @GetMapping + public ResponseEntity> getAll() { + logger.info("Fetching all history records"); + return ResponseEntity.ok(historyService.getAll()); + } + + // GET /history/{id} — returns one record by ID + @GetMapping("/{id}") + public ResponseEntity getById(@PathVariable Long id) { + logger.info("Fetching history record with id: {}", id); + return historyService.getById(id) + .map(ResponseEntity::ok) // found → 200 OK + .orElse(ResponseEntity.notFound().build()); // not found → 404 + } + + // PUT /history/{id} — fully update a record by ID + @PutMapping("/{id}") + public ResponseEntity update( + @PathVariable Long id, + @RequestBody ConversionHistory updated) { + logger.info("Updating history record with id: {}", id); + return historyService.update(id, updated) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + // PATCH /history/{id} — partially update a record by ID (same logic as PUT here) + @PatchMapping("/{id}") + public ResponseEntity patch( + @PathVariable Long id, + @RequestBody ConversionHistory updated) { + logger.info("Patching history record with id: {}", id); + return historyService.update(id, updated) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + // DELETE /history — clears all history records + @DeleteMapping + public ResponseEntity deleteAll() { + logger.info("Deleting all history records"); + historyService.deleteAll(); + return ResponseEntity.noContent().build(); // 204 No Content + } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/model/ConversionHistory.java b/src/main/java/com/oraclequantapi/oraclequantapi/model/ConversionHistory.java new file mode 100644 index 0000000..b3df891 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/model/ConversionHistory.java @@ -0,0 +1,52 @@ +package com.oraclequantapi.oraclequantapi.model; + +import jakarta.persistence.*; +import java.time.LocalDateTime; + +// This class represents a database table row for storing conversion history +@Entity +@Table(name = "conversion_history") +public class ConversionHistory { + + // Auto-generated primary key + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + // Time when the request was made: + private LocalDateTime timestamp; + + // IP address of the client who made the request + @Column(name = "source_ip_address") + private String sourceIpAddress; + + // The input string sent by the client + @Column(length = 1000) + private String input; + + // The result returned to the client: + @Column(length = 2000) + private String output; + + // Empty constructor required by JPA + public ConversionHistory() {} + + // Getters and Setters: + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public LocalDateTime getTimestamp() { return timestamp; } + public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; } + + public String getSourceIpAddress() { return sourceIpAddress; } + public void setSourceIpAddress(String sourceIpAddress) { + this.sourceIpAddress = sourceIpAddress; + } + + public String getInput() { return input; } + public void setInput(String input) { this.input = input; } + + public String getOutput() { return output; } + public void setOutput(String output) { this.output = output; } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/repository/HistoryRepository.java b/src/main/java/com/oraclequantapi/oraclequantapi/repository/HistoryRepository.java new file mode 100644 index 0000000..46f6733 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/repository/HistoryRepository.java @@ -0,0 +1,12 @@ +package com.oraclequantapi.oraclequantapi.repository; + +import com.oraclequantapi.oraclequantapi.model.ConversionHistory; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +// This interface handles all database operations for ConversionHistory +// JpaRepository automatically provides: save, findAll, findById, deleteAll, etc. +@Repository +public interface HistoryRepository extends JpaRepository { + // No extra methods needed — JPA covers all required operations +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/service/ConversionService.java b/src/main/java/com/oraclequantapi/oraclequantapi/service/ConversionService.java new file mode 100644 index 0000000..0681fef --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/service/ConversionService.java @@ -0,0 +1,71 @@ +package com.oraclequantapi.oraclequantapi.service; + +import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; + +// This service contains the core algorithm for converting the input string +@Service +public class ConversionService { + + // Main method: converts an encoded input string into a list of package totals + public List convert(String input) { + List result = new ArrayList<>(); + int i = 0; + + while (i < input.length()) { + // Read the counter — tells us how many values are in this package + int[] counterRead = readNumber(input, i); + int counter = counterRead[0]; // number of values to read + i = counterRead[1]; // move index forward + + // Sum up the next 'counter' values + int sum = 0; + for (int j = 0; j < counter; j++) { + if (i >= input.length()) break; // safety check — avoid out of bounds + int[] valRead = readNumber(input, i); + sum += valRead[0]; // add value to package total + i = valRead[1]; // move index forward + } + + // Add this package's total to the result list + result.add(sum); + } + + return result; + } + + // Reads a single encoded number starting at position 'pos' + // Rules: + // - Each letter maps to a number: a=1, b=2, ..., z=26 + // - If the letter is 'z', keep reading and adding (multi-char number) + // - If the letter is '_', it means 0 and ends the number + // - Any other letter ends the number after being added + private int[] readNumber(String input, int pos) { + int total = 0; + + while (pos < input.length()) { + char c = input.charAt(pos); + + if (c == '_') { + // Underscore means 0 — end of this number + pos++; + break; + } + + // Convert letter to its numeric value (a=1, b=2, ..., z=26) + int val = c - 'a' + 1; + total += val; + pos++; + + if (c != 'z') { + // Non-z letter ends the number + break; + } + // If c == 'z', continue reading the next character and add it too + } + + // Return both the number value and the updated index position + return new int[]{total, pos}; + } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/service/HistoryService.java b/src/main/java/com/oraclequantapi/oraclequantapi/service/HistoryService.java new file mode 100644 index 0000000..730c52c --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/service/HistoryService.java @@ -0,0 +1,52 @@ +package com.oraclequantapi.oraclequantapi.service; + +import com.oraclequantapi.oraclequantapi.model.ConversionHistory; +import com.oraclequantapi.oraclequantapi.repository.HistoryRepository; +import org.springframework.stereotype.Service; +import java.util.List; +import java.util.Optional; + +// This service handles all business logic related to history records +@Service +public class HistoryService { + + // Injected repository for database access + private final HistoryRepository historyRepository; + + // Constructor injection (recommended over @Autowired) + public HistoryService(HistoryRepository historyRepository) { + this.historyRepository = historyRepository; + } + + // Save a new history record to the database + public ConversionHistory save(ConversionHistory record) { + return historyRepository.save(record); + } + + // Retrieve all history records + public List getAll() { + return historyRepository.findAll(); + } + + // Retrieve a single record by its ID + public Optional getById(Long id) { + return historyRepository.findById(id); + } + + // Update an existing record — only updates fields that are not null + public Optional update(Long id, ConversionHistory updated) { + return historyRepository.findById(id).map(existing -> { + // Only overwrite fields if the new value is provided + if (updated.getInput() != null) existing.setInput(updated.getInput()); + if (updated.getOutput() != null) existing.setOutput(updated.getOutput()); + if (updated.getSourceIpAddress() != null) + existing.setSourceIpAddress(updated.getSourceIpAddress()); + return historyRepository.save(existing); // save updated record + }); + } + + // Delete all history records from the database + public void deleteAll() { + historyRepository.deleteAll(); + } +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 99d0060..56c5502 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,15 @@ spring.application.name=oraclequantapi +spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE +spring.datasource.username=system +spring.datasource.password=29999login +spring.datasource.driver-class-name=oracle.jdbc.OracleDriver + +spring.jpa.hibernate.ddl-auto=update +spring.jpa.database-platform=org.hibernate.dialect.OracleDialect +spring.jpa.show-sql=true + +server.port=8080 + +logging.file.name=logs/pkc-api.log +logging.logback.rollingpolicy.max-history=7 +logging.level.com.oraclequantapi=INFO \ No newline at end of file diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..84eae65 --- /dev/null +++ b/version.txt @@ -0,0 +1,6 @@ +Version 1.0.0 +- GET /convert-measurements endpoint +- History CRUD endpoints (GET, PUT, PATCH, DELETE) +- Oracle XE Database integration +- Rolling log files (7 days) +- README.md documentation