diff --git a/CHANGLOG.md b/CHANGLOG.md new file mode 100644 index 0000000..248a6b4 --- /dev/null +++ b/CHANGLOG.md @@ -0,0 +1,23 @@ +# Change Log + +## Version 1.0 + +### Added +Created REST API using Spring Boot +Added Oracle XE database connection +Added conversion endpoint +Added history save functionality +Added get all history endpoint +Added get history by ID endpoint +Added update history endpoint +Added delete history endpoint +Added README documentation + +### Updated +Updated application properties configuration +Improved service layer logic + +### Fixed +Fixed database save issue +Fixed update endpoint issues +Fixed delete endpoint response \ No newline at end of file diff --git a/README.md b/README.md index b1cccfd..10f1665 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,124 @@ -## 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. +# History Conversion API + +A Spring Boot REST API that converts input strings into numeric values and stores the conversion history in an Oracle XE database. + +--- + +## Features + +Convert input strings into numeric output +Save conversion history in Oracle XE +Get all history records +Get a history record by ID +Update a history record +Delete a history record +REST API using Spring Boot + +--- + +## Technologies Used + +Java 17 +Spring Boot +Maven +Oracle XE +Docker +Postman + +--- + +## API Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/convert-measurements?input=aa` | Convert input and save history | +| GET | `/history` | Get all history | +| GET | `/history/{id}` | Get history by ID | +| PUT | `/history/{id}` | Update history | +| DELETE | `/history/{id}` | Delete history | + +--- + +## Example Request + +### Convert Input +```http +GET http://localhost:8080/convert-measurements?input=aa +``` + +### Example Response +```json +[1] +``` + +--- + +## Update Example + +### Request +```http +PUT http://localhost:8080/history/1 +``` + +### Body +```json +{ + "input": "updated", + "output": "[99]", + "sourceIpAddress": "127.0.0.1", + "timestamp": "updated" +} +``` + +--- + +## Delete Example + +### Request +```http +DELETE http://localhost:8080/history/1 +``` + +### Response +```text +History record deleted successfully +``` + +--- + +## Database Configuration + +```properties +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.hibernate.ddl-auto=update +spring.jpa.show-sql=true +``` + +--- + +## Running the Project + +```bash +mvn spring-boot:run +``` + +The application will run on: + +```text +http://localhost:8080 +``` + +--- + +## Testing + +The API was tested using Postman for: +GET +PUT +DELETE + +All endpoints worked successfully. \ No newline at end of file diff --git a/pom.xml b/pom.xml index 20909d2..7a03eea 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,35 @@ spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.oracle.database.jdbc + ojdbc11 + runtime + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java b/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java index 5e28689..b23e044 100644 --- a/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java +++ b/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java @@ -10,4 +10,4 @@ public static void main(String[] args) { SpringApplication.run(OraclequantapiApplication.class, args); } -} +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/controllers/ConversionController.java b/src/main/java/com/oraclequantapi/oraclequantapi/controllers/ConversionController.java new file mode 100644 index 0000000..2731e82 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/controllers/ConversionController.java @@ -0,0 +1,32 @@ +package com.oraclequantapi.oraclequantapi.controllers; + +import com.oraclequantapi.oraclequantapi.services.ConversionService; +import com.oraclequantapi.oraclequantapi.services.HistoryService; +import jakarta.servlet.http.HttpServletRequest; +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 ConversionController { + + private final ConversionService conversionService; + private final HistoryService historyService; + + public ConversionController(ConversionService conversionService, HistoryService historyService) { + this.conversionService = conversionService; + this.historyService = historyService; + } + + @GetMapping("/convert-measurements") + public List convertMeasurements(@RequestParam String input, HttpServletRequest request) { + + List result = conversionService.convertMeasurements(input); + + historyService.saveHistory(input, result.toString(), request.getRemoteAddr()); + + return result; + } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/controllers/HistoryController.java b/src/main/java/com/oraclequantapi/oraclequantapi/controllers/HistoryController.java new file mode 100644 index 0000000..b9472a5 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/controllers/HistoryController.java @@ -0,0 +1,46 @@ +package com.oraclequantapi.oraclequantapi.controllers; + +import com.oraclequantapi.oraclequantapi.models.HistoryRecord; +import com.oraclequantapi.oraclequantapi.services.HistoryService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@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 HistoryRecord getHistoryById(@PathVariable Long id) { + return historyService.getHistoryById(id); + } + + @PutMapping("/{id}") + public HistoryRecord updateHistory(@PathVariable Long id, + @RequestBody HistoryRecord updatedRecord) { + return historyService.updateHistory(id, updatedRecord); + } + + @DeleteMapping + public String clearHistory() { + historyService.clearHistory(); + return "History cleared successfully"; + } + + @DeleteMapping("/{id}") + public String deleteHistoryById(@PathVariable Long id) { + historyService.deleteHistoryById(id); + return "History record deleted successfully"; + } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/models/HistoryRecord.java b/src/main/java/com/oraclequantapi/oraclequantapi/models/HistoryRecord.java new file mode 100644 index 0000000..18d3356 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/models/HistoryRecord.java @@ -0,0 +1,72 @@ +package com.oraclequantapi.oraclequantapi.models; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity +public class HistoryRecord { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String input; + + private String output; + + private String sourceIpAddress; + + private String timestamp; + + public HistoryRecord() { + } + + public HistoryRecord(String input, String output, String sourceIpAddress, String timestamp) { + this.input = input; + this.output = output; + this.sourceIpAddress = sourceIpAddress; + this.timestamp = timestamp; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + 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; + } + + public String getSourceIpAddress() { + return sourceIpAddress; + } + + public void setSourceIpAddress(String sourceIpAddress) { + this.sourceIpAddress = sourceIpAddress; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/repositories/HistoryRepository.java b/src/main/java/com/oraclequantapi/oraclequantapi/repositories/HistoryRepository.java new file mode 100644 index 0000000..0b440e1 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/repositories/HistoryRepository.java @@ -0,0 +1,10 @@ +package com.oraclequantapi.oraclequantapi.repositories; + +import com.oraclequantapi.oraclequantapi.models.HistoryRecord; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface HistoryRepository extends JpaRepository { + +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/services/ConversionService.java b/src/main/java/com/oraclequantapi/oraclequantapi/services/ConversionService.java new file mode 100644 index 0000000..04bbe49 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/services/ConversionService.java @@ -0,0 +1,63 @@ +package com.oraclequantapi.oraclequantapi.services; + +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class ConversionService { + + public List convertMeasurements(String input) { + + List results = new ArrayList<>(); + + int index = 0; + + while (index < input.length()) { + + char counterChar = input.charAt(index); + + int counter = getCharacterValue(counterChar); + + index++; + + int sum = 0; + + for (int i = 0; i < counter && index < input.length(); i++) { + + char currentChar = input.charAt(index); + + sum += getCharacterValue(currentChar); + + while (currentChar == 'z' && index + 1 < input.length()) { + + index++; + + currentChar = input.charAt(index); + + sum += getCharacterValue(currentChar); + + if (currentChar != 'z') { + break; + } + } + + index++; + } + + results.add(sum); + } + + return results; + } + + private int getCharacterValue(char c) { + + if (c == '_') { + return 0; + } + + return (c - 'a') + 1; + } +} \ No newline at end of file diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/services/HistoryService.java b/src/main/java/com/oraclequantapi/oraclequantapi/services/HistoryService.java new file mode 100644 index 0000000..19c8d7b --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/services/HistoryService.java @@ -0,0 +1,62 @@ +package com.oraclequantapi.oraclequantapi.services; + +import com.oraclequantapi.oraclequantapi.models.HistoryRecord; +import com.oraclequantapi.oraclequantapi.repositories.HistoryRepository; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; + +@Service +public class HistoryService { + + private final HistoryRepository historyRepository; + + public HistoryService(HistoryRepository historyRepository) { + this.historyRepository = historyRepository; + } + + public void saveHistory(String input, String output, String sourceIpAddress) { + + HistoryRecord record = new HistoryRecord(); + + record.setInput(input); + record.setOutput(output); + record.setSourceIpAddress(sourceIpAddress); + record.setTimestamp(LocalDateTime.now().toString()); + + historyRepository.save(record); + } + + public List getAllHistory() { + return historyRepository.findAll(); + } + + public HistoryRecord getHistoryById(Long id) { + return historyRepository.findById(id).orElse(null); + } + + public HistoryRecord updateHistory(Long id, HistoryRecord updatedRecord) { + + HistoryRecord existingRecord = historyRepository.findById(id).orElse(null); + + if (existingRecord != null) { + existingRecord.setInput(updatedRecord.getInput()); + existingRecord.setOutput(updatedRecord.getOutput()); + existingRecord.setSourceIpAddress(updatedRecord.getSourceIpAddress()); + existingRecord.setTimestamp(updatedRecord.getTimestamp()); + + return historyRepository.save(existingRecord); + } + + return null; + } + + public void clearHistory() { + historyRepository.deleteAll(); + } + + public void deleteHistoryById(Long id) { + historyRepository.deleteById(id); + } +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 99d0060..298f63d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,12 @@ spring.application.name=oraclequantapi + +server.port=8080 + +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.hibernate.ddl-auto=update +spring.jpa.database-platform=org.hibernate.dialect.OracleDialect +spring.jpa.show-sql=true \ No newline at end of file