Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

---

# CHANGELOG.md

```markdown id="changelog_final"
# CHANGELOG

---

## [1.0.0] - 2026-05-25

### Added
- Implemented full Sequence Processing REST API using Spring Boot.
- Added `/sequences/convert-measurements` endpoint for stream-based sequence computation.
- Introduced stateful streaming algorithm for dynamic grouping of input characters.
- Added Oracle Database persistence layer (SEQUENCE_HISTORY table).
- Implemented full history management (GET, PUT, DELETE operations).
- Added SLF4J logging for request tracing and debugging.
- Added input validation for allowed characters (a-z and underscore `_`).

### Changed
- Refactored architecture to a clean layered design (Controller → Service → Repository).
- Updated processing logic to support dynamic stream traversal instead of static parsing.
- Improved grouping logic to support runtime state transitions.

### Fixed
- Fixed schema mismatch issues between Oracle CLOB and entity mappings.
- Resolved Spring Boot ApplicationContext startup issues caused by schema validation conflicts.
- Fixed history persistence inconsistencies in output formatting.

---

## [0.2.0] - 2026-05-24

### Added
- Introduced sequence processing service layer.
- Added Oracle JPA repository integration.
- Enabled automatic persistence of conversion results into database.

---

## [0.1.0] - 2026-05-23

### Added
- Initial implementation of REST API.
- Basic sequence processing logic.
- Simple endpoint for conversion testing.

---

## [0.0.1] - 2026-05-21

### Added
- Project initialization using Spring Boot.
- Maven configuration setup.
- Base REST controller structure created.
135 changes: 74 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,61 +1,74 @@
## 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 Sequence API

## Overview
This is a Spring Boot REST API that processes input character sequences using a custom stateful streaming algorithm.

The system converts sequences into numeric package results, applies dynamic grouping logic based on control characters, and persists all transactions into an Oracle Database.

---

## Core Concept
The algorithm processes input as a **stream of characters**, not static chunks.

- The character `z` acts as a **control/boundary modifier**
- The character `_` is treated as **neutral (value = 0)**
- Processing is based on **stateful traversal and lookahead accumulation**
- Groups are dynamically formed during runtime execution

---

## Tech Stack
- Java 17+
- Spring Boot
- Spring Web
- Spring Data JPA
- Oracle Database (XE / XEPDB1)
- SLF4J Logging
- Maven

---

## Base URL


http://localhost:8080/sequences


---

## API Endpoints

### 1. Convert Measurements
Processes a sequence and returns computed package totals.


GET /sequences/convert-measurements?input=abbcc


**Example Response**
```json
[2, 6]
2. Get All History
GET /sequences/history
3. Get History By ID
GET /sequences/history/{id}
4. Update History
PUT /sequences/history/{id}

Body

{
"input": "abc",
"output": "[2,6]",
"sourceIpAddress": "127.0.0.1"
}
5. Delete All History
DELETE /sequences/history
6. Delete History By ID
DELETE /sequences/history/{id}
# Algorithm Behavior
Input is processed as a continuous stream
z acts as a state modifier / boundary controller
_ contributes value 0 without breaking flow
Output is generated using dynamic grouping + lookahead accumulation
Final result is a list of computed package totals
10 changes: 9 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package com.oraclequantapi.oraclequantapi.controllers;
import com.oraclequantapi.oraclequantapi.models.Sequence;
import com.oraclequantapi.oraclequantapi.models.SequenceHistory;
import com.oraclequantapi.oraclequantapi.services.SequenceService;
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.util.List;

@RestController
@RequestMapping("/sequences")
public class SequenceController {
private static final Logger log = LoggerFactory.getLogger(SequenceController.class);

private final SequenceService service;

public SequenceController(SequenceService service) {
this.service = service;
}

// =========================
// CONVERT ENDPOINT
// =========================
@GetMapping("/convert-measurements")
public ResponseEntity<List<Integer>> convertMeasurements(
@RequestParam("input") String input,
HttpServletRequest request) {

String sourceIp = request.getRemoteAddr();

log.info("Conversion request - input: \"{}\", source IP: {}", input, sourceIp);

Sequence sequence = new Sequence(input);

if (!sequence.is_valid()) {
log.warn("Invalid input received: \"{}\"", input);
return ResponseEntity.badRequest().build();
}

List<Integer> result = service.process_sequence(sequence, sourceIp);

log.info("Conversion result - input: \"{}\", output: {}", input, result);

return ResponseEntity.ok(result);
}

// =========================
// HISTORY - GET ALL
// =========================
@GetMapping("/history")
public ResponseEntity<List<SequenceHistory>> getAllHistory() {

log.info("Fetching all history records");

List<SequenceHistory> records = service.getAllHistory();

log.info("Fetched {} history records", records.size());

return ResponseEntity.ok(records);
}

// =========================
// HISTORY - GET BY ID
// =========================
@GetMapping("/history/{id}")
public ResponseEntity<SequenceHistory> getHistoryById(@PathVariable Long id) {

log.info("Fetching history record by id: {}", id);
return service.getHistoryById(id).map(record -> {
log.info("Found history record: {}", id);
return ResponseEntity.ok(record);
})
.orElseGet(() -> {
log.warn("History record not found: {}", id);
return ResponseEntity.notFound().build();
});
}

// =========================
// HISTORY - UPDATE
// =========================
@PutMapping("/history/{id}")
public ResponseEntity<SequenceHistory> updateHistory(
@PathVariable Long id,
@RequestBody SequenceHistory record) {

log.info("Updating history record: {}", id);

try {
SequenceHistory updated = service.updateHistory(id, record);
log.info("Updated history record: {}", id);
return ResponseEntity.ok(updated);

} catch (RuntimeException e) {
log.warn("Update failed - record not found: {}", id);
return ResponseEntity.notFound().build();
}
}

// =========================
// HISTORY - DELETE ALL
// =========================
@DeleteMapping("/history")
public ResponseEntity<Void> clearHistory() {

log.info("Clearing all history records");

service.deleteHistory();

log.info("All history records cleared");

return ResponseEntity.noContent().build();
}

// =========================
// HISTORY - DELETE BY ID (ADDED like sample solution)
// =========================
@DeleteMapping("/history/{id}")
public ResponseEntity<Void> deleteHistoryById(@PathVariable Long id) {

log.info("Deleting history record: {}", id);

boolean exists = service.getHistoryById(id).isPresent();

if (!exists) {
log.warn("Delete failed - record not found: {}", id);
return ResponseEntity.notFound().build();
}

service.deleteHistoryById(id);

log.info("Deleted history record: {}", id);

return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.oraclequantapi.oraclequantapi.models;
import java.util.ArrayList;
import java.util.List;
public class Sequence {
private final List<String> value;

public Sequence() {
this.value = new ArrayList<>();
}

public Sequence(String rawInput) {
this.value = new ArrayList<>();
set_value(rawInput);
}

public void set_value(String rawInput) {
this.value.clear();
if (rawInput != null) {
for (char ch : rawInput.toCharArray()) {
this.value.add(String.valueOf(ch));
}
}
}

public String get_value_as_str() {
return String.join("", this.value);
}

public boolean is_valid() {
if (this.value == null || this.value.isEmpty()) {
return false;
}
for (String s : this.value) {
char ch = s.charAt(0);
if ((ch < 'a' || ch > 'z') && ch != '_') {
return false;
}
}
return true;
}

public List<String> getValue() {
return value;
}
}
Loading