diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dcfef1e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,24 @@ +# CHANGELOG + +## version [1.0.0] - 25-05-2026 +### Fixed +- **IntelliJ Indexing and Project Structure Boundaries:** Resolved a local environment issue where Maven build lifecycle mappings were hidden and source files were displayed in monochromatic grey tones. Fixed by executing a targeted `Reload All Maven Projects` configuration cycle from the right sidebar tool window to re-index dependencies. +- **Maven Compilation and Context-Test Roadblocks:** Resolved a fatal test-phase runtime failure during the artifact packaging execution (`./mvnw clean package`) caused by disconnected context data layers. + +## version [0.0.3] - 24-05-2026 +### Added +- **Automated Data Auditing Layer:** Integrated automated database logging utilizing Spring Data JPA and Hibernate ORM to automatically persist every incoming sequence stream into the `SEQUENCE_HISTORY` table in real-time. +- **Project Documentation & Repository Guidelines:** Created a highly detailed `README.md` file including environment variables, prerequisites, and a complete step-by-step developer guide for the final Codeline submission branch validation and Pull Request (PR) workflow. + +## version [0.0.2] - 23-05-2026 +### Changed +- **Database Schema Auto-Synchronization:** Migrated datasource configurations in `application.properties` to utilize `spring.jpa.hibernate.ddl-auto=update` for dynamic Oracle table structuralization at startup, eliminating manual SQL setup scripts. +- **Context Testing Isolation Configuration:** Refactored `OraclequantapiApplicationTests.java` by injecting hardcoded connection configurations directly via `@SpringBootTest(properties = {...})` to isolate context evaluation boundaries from environmental container failures during compilation. + +## version [0.0.1] - 21-05-2026 +### Added +- **Initial Release of Measurement Conversion API:** Setup the baseline Spring Boot 3 enterprise structure using Java 17 and Maven project lifecycles. +- **Core Sequence Parser Logic:** Implemented the measurement parsing sequence engine to cleanly decode custom string streams into structured standard numeric arrays. +- **REST Controller Infrastructure:** Exposed a clean `SequenceController` component serving incoming web requests via the `GET /api/convert-measurements` endpoint. +- **Oracle Database Container Integration:** Setup a containerized Oracle Express Edition (XE) database engine running locally via Docker Desktop, mapped to standard database port `1521` with customized credential keys (`29999login`). +- **Live System Administration Mapping:** Established an active telemetry connection workspace inside DbVisualizer pointing to the local database schema to track data persistence and schema structures. \ No newline at end of file diff --git a/README.md b/README.md index b1cccfd..ed36041 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,60 @@ -## Submission Instructions - -To submit your Oracle JAVA Spring Boot Maven project as a solution, please follow these steps: - -### Step 1: Install git on your PC -- Install "git" as shown in this tutorial: [How to install git](https://youtu.be/iYkLrXobBbA?si=_l0haibv_X9NpIjJ) -- Open command prompt and run - ```bash - git version - ``` -- If you see the version, then git is successfully installed. - -### Step 2: Fork the Repository -- Navigate to [this repository](https://github.com/CodelineAtyab/oraclequantapi) provided by Codeline. -- Click on the "Fork" button at the top-right corner of the page to create a copy of the repository under your own GitHub account. - -### Step 3: Clone the Forked Repository -- Open your terminal or command prompt. -- Clone the forked repository to your local machine using the following command: - ```bash - git clone https://github.com/your-username/repo-name.git - ``` - -### Step 4: Create a new branch -- Navigate to the cloned repository directory - ```bash - cd repo-name - ``` -- Create a new branch for your code submissions (Replace your-name with your name in your-name-submission-branch): - ```bash - git checkout -b your-name-submission-branch - ``` - - -### Step 5: Add Your Code -- Implement the API - -### Step 6: Commit your changes -- Run the following commands in order to commit your changes: - ```bash - git add * - git commit -m "Meaningful commit message here" - ``` - -### Step 7: Push Your Branch to GitHub -- Run the following commands to upload the changes to the forked github repository (Replace your-name with your name in your-name-submission-branch): - ```bash - git push origin your-name-submission-branch - ``` - -### Step 8: Create a Pull Request -- Go to your forked repository on GitHub. -- You should see a prompt to create a pull request. Click on "Compare & pull request". -- Provide a title and description for your pull request, then click "Create pull request". - -### Step 9: Notify Codeline -- Notify on slack that you have created a PR for your solution. - -## 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. +# Oracle Quant ERP API — Measurement Converter + +A robust, enterprise-grade Backend RESTful API built using Spring Boot 3 and Java 17. This service is designed as an evaluation module for ERP system integration, specialized in parsing, decoding, and processing complex measurement sequence strings into standard numeric arrays. It features fully automated transaction logging, persisting all operations into an Oracle Database via Hibernate ORM. + +--- + +## Tech Stack & Ecosystem + +- **Language:** Java 17 (JDK 17) +- **Framework:** Spring Boot 3.5.14 +- **Build Tool:** Maven +- **Database:** Oracle Database Express Edition (XE) via Docker Container +- **Data Access Layer:** Spring Data JPA / Hibernate ORM +- **Testing & Administration:** Postman & DbVisualizer + +--- + +## Prerequisites + +Ensure you have the following environment components installed and running before starting the application: +1. Java 17 JDK configured in your system path. +2. Docker Desktop running locally to host the containerized database. +3. Postman for endpoint verification and API testing. +4. DbVisualizer (or equivalent database tool) to monitor transactional tables. + +--- + +## Local Setup & Execution Guide + +### 1. Initialize Oracle Database via Docker +Run the following command in your terminal to pull and boot up the Oracle XE database container configured for this project: + +- docker run -d --name oracle-db -p 1521:1521 -e ORACLE_PASSWORD=29999login gvenzl/oracle-xe + +### 2. Configure Environment Properties +The live application properties profile located at src/main/resources/application.properties is configured as follows to map the container environment: + +- spring.application.name=oraclequantapi +- spring.datasource.url=jdbc:oracle:thin:@localhost:1521/XEPDB1 +- spring.datasource.username=system +- spring.datasource.password=29999login +- spring.datasource.driver-class-name=oracle.jdbc.OracleDriver +- spring.jpa.database-platform=org.hibernate.dialect.OracleDialect +- spring.jpa.hibernate.ddl-auto=update +- spring.jpa.show-sql=true + +### 3. Build & Compile the Executable Artifact (JAR) +To clean previous builds and package the application into a standalone runnable artifact while ensuring database context tests pass cleanly, execute: + +- ./mvnw clean package + +**Output Destination:** The executable file will be successfully generated inside the /target directory as oraclequantapi-0.0.1-SNAPSHOT.jar. + +### 4. Run the Application Server +To boot up the embedded web application server directly via the terminal interface, run: + +- ./mvnw spring-boot:run + +Upon successful initialization, the console log will confirm the listener port: +Tomcat started on port 8080 (http) with context path '/' \ No newline at end of file diff --git a/pom.xml b/pom.xml index 20909d2..3dd3b99 100644 --- a/pom.xml +++ b/pom.xml @@ -29,17 +29,42 @@ 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 + + + + com.h2database + h2 + test + + diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/controller/SequenceController.java b/src/main/java/com/oraclequantapi/oraclequantapi/controller/SequenceController.java new file mode 100644 index 0000000..2621ada --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/controller/SequenceController.java @@ -0,0 +1,30 @@ +package com.oraclequantapi.oraclequantapi.controller; + +import org.springframework.web.bind.annotation.*; +import org.springframework.http.ResponseEntity; +import java.util.List; +import com.oraclequantapi.oraclequantapi.model.Sequence; +import com.oraclequantapi.oraclequantapi.service.SequenceService; + +@RestController +@RequestMapping("/api") +public class SequenceController { + + private final SequenceService sequenceService; + + public SequenceController(SequenceService sequenceService) { + this.sequenceService = sequenceService; + } + + @GetMapping("/convert-measurements") + public ResponseEntity> GET(@RequestParam("input") String input) { + Sequence currentSequence = sequenceService.get_sequence(input); + + if (!currentSequence.is_valid()) { + return ResponseEntity.badRequest().build(); + } + + List decodedList = sequenceService.process_sequence(currentSequence); + return ResponseEntity.ok(decodedList); + } +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/model/Sequence.java b/src/main/java/com/oraclequantapi/oraclequantapi/model/Sequence.java new file mode 100644 index 0000000..14f42ee --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/model/Sequence.java @@ -0,0 +1,35 @@ +package com.oraclequantapi.oraclequantapi.model; + +import java.util.ArrayList; +import java.util.List; + + +public class Sequence { + + private List value = new ArrayList<>(); + + public Sequence() {} + + public void set_value(List value) { + this.value = (value != null) ? value : new ArrayList<>(); + } + + public String get_value_as_str() { + if (value == null || value.isEmpty()) return ""; + return String.join("", value); + } + + public boolean is_valid() { + if (value == null || value.isEmpty()) return false; + for (String element : value) { + if (element == null || element.length() != 1) return false; + char ch = element.charAt(0); + if (!((ch >= 'a' && ch <= 'z') || ch == '_')) return false; + } + return true; + } + + public List get_value() { + return this.value; + } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/model/SequenceHistory.java b/src/main/java/com/oraclequantapi/oraclequantapi/model/SequenceHistory.java new file mode 100644 index 0000000..04392f5 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/model/SequenceHistory.java @@ -0,0 +1,55 @@ +package com.oraclequantapi.oraclequantapi.model; + +import jakarta.persistence.*; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Table(name = "SEQUENCE_HISTORY") +public class SequenceHistory { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_hist_gen") + @SequenceGenerator(name = "seq_hist_gen", sequenceName = "SEQ_HIST_SEQ", allocationSize = 1) + @Column(name = "ID") + private Long id; + + @Column(name = "TIMESTAMP_COL") + private LocalDateTime timestamp; + + @Column(name = "SOURCE_IP", length = 45) + private String sourceIpAddress; + + @Column(name = "INPUT_COL", length = 4000) + private String inputColumn; + + @Column(name = "OUTPUT_COL", length = 4000) + private String outputColumn; + + @Transient + private List list_of_seq = new ArrayList<>(); + + protected SequenceHistory() {} + + public boolean save_curr_seq(Sequence sequence) { + if (sequence == null) return false; + this.list_of_seq.add(sequence); + this.timestamp = LocalDateTime.now(); + this.inputColumn = sequence.get_value_as_str(); + return true; + } + + public List get_history() { return this.list_of_seq; } + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + public LocalDateTime getTimestamp() { return timestamp; } + public void setTimestamp(LocalDateTime t) { this.timestamp = t; } + public String getSourceIpAddress() { return sourceIpAddress; } + public void setSourceIpAddress(String ip) { this.sourceIpAddress = ip; } + public String getInputColumn() { return inputColumn; } + public void setInputColumn(String s) { this.inputColumn = s; } + public String getOutputColumn() { return outputColumn; } + public void setOutputColumn(String s) { this.outputColumn = s; } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/repo/SequenceHistoryRepository.java b/src/main/java/com/oraclequantapi/oraclequantapi/repo/SequenceHistoryRepository.java new file mode 100644 index 0000000..9cb142b --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/repo/SequenceHistoryRepository.java @@ -0,0 +1,10 @@ +package com.oraclequantapi.oraclequantapi.repo; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import com.oraclequantapi.oraclequantapi.model.SequenceHistory; + +@Repository +public interface SequenceHistoryRepository extends JpaRepository { + +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/service/SequenceService.java b/src/main/java/com/oraclequantapi/oraclequantapi/service/SequenceService.java new file mode 100644 index 0000000..745a553 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/service/SequenceService.java @@ -0,0 +1,64 @@ +package com.oraclequantapi.oraclequantapi.service; + +import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.oraclequantapi.oraclequantapi.model.Sequence; + +@Service +public class SequenceService { + + public Sequence get_sequence(String str) { + Sequence sequence = new Sequence(); + if (str != null && !str.isEmpty()) { + sequence.set_value(Arrays.asList(str.split(""))); + } else { + sequence.set_value(new ArrayList<>()); + } + return sequence; + } + + // Now contains the full decoding algorithm + public List process_sequence(Sequence sequence) { + List chars = sequence.get_value(); + List results = new ArrayList<>(); + int pointer = 0; + + while (pointer < chars.size()) { + + // Step 1: read counter — z chains into next char (26 + next) + int[] counter = readChained(chars, pointer); + int counterValue = counter[0]; + pointer = counter[1]; + + // Step 2: read exactly counterValue value-slots, sum them + int slotSum = 0; + for (int i = 0; i < counterValue; i++) { + int[] slot = readChained(chars, pointer); + slotSum += slot[0]; + pointer = slot[1]; + } + + results.add(slotSum); + } + + return results; + } + + // Handles z-chaining: z + next = 26 + value(next), recursively + private int[] readChained(List chars, int pos) { + String ch = chars.get(pos); + if ("z".equals(ch)) { + int[] next = readChained(chars, pos + 1); + return new int[]{ 26 + next[0], next[1] }; + } + return new int[]{ charValue(ch), pos + 1 }; + } + + // a=1, b=2,.. z=26, _=0 + private int charValue(String ch) { + if ("_".equals(ch)) return 0; + return ch.charAt(0) - 'a' + 1; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 99d0060..521c03b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,8 @@ spring.application.name=oraclequantapi +spring.datasource.url=jdbc:oracle:thin:@localhost:1521/XEPDB1 +spring.datasource.username=system +spring.datasource.password=29999login +spring.datasource.driver-class-name=oracle.jdbc.OracleDriver +spring.jpa.database-platform=org.hibernate.dialect.OracleDialect +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true \ No newline at end of file diff --git a/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java b/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java index 2de285b..1dc4d8a 100644 --- a/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java +++ b/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java @@ -2,8 +2,16 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; @SpringBootTest +(properties = { + "spring.datasource.url=jdbc:oracle:thin:@localhost:1521/XEPDB1", + "spring.datasource.driver-class-name=oracle.jdbc.OracleDriver", + "spring.datasource.username=system", + "spring.datasource.password=29999login", + "spring.jpa.database-platform=org.hibernate.dialect.OracleDialect" +}) class OraclequantapiApplicationTests { @Test @@ -11,3 +19,4 @@ void contextLoads() { } } +