Skip to content

Commit

Permalink
Fix swagger generated response, use a specific class
Browse files Browse the repository at this point in the history
  • Loading branch information
zakariamaaraki committed Jan 7, 2024
1 parent 1850050 commit 0f73ab1
Show file tree
Hide file tree
Showing 38 changed files with 749 additions and 412 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.cp.compiler.contract;

import io.swagger.annotations.ApiModelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@EqualsAndHashCode
public class BaseRemoteCodeCompilerResponse {

@ApiModelProperty(notes = "The error message")
private String error;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.cp.compiler.contract;

import com.cp.compiler.contract.testcases.TestCaseResult;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;

// Note: Before changing this class make sure it will not introduce a breaking change for users!!

/**
* The type Response.
* This represents the response returned to the user.
*
* @author Zakaria Maaraki
*/
@Getter
@NoArgsConstructor
@EqualsAndHashCode
@ApiModel(description = "The returned response")
public class RemoteCodeCompilerExecutionResponse
{

/**
* Instantiates a new Response.
*
* @param verdict the statusResponse
* @param statusCode the status code
* @param error the error
* @param testCasesResult the test cases result
* @param compilationDuration the compilation duration
* @param timeLimit the time limit
* @param memoryLimit the memory limit
* @param language the language
* @param localDateTime the local date time
*/
public RemoteCodeCompilerExecutionResponse(String verdict,
int statusCode,
String error,
LinkedHashMap<String, TestCaseResult> testCasesResult,
int compilationDuration,
int timeLimit,
int memoryLimit,
Language language,
LocalDateTime localDateTime) {
this.verdict = verdict;
this.statusCode = statusCode;
this.error = error;
this.testCasesResult = testCasesResult;
this.compilationDuration = compilationDuration;
this.timeLimit = timeLimit * 1000; // convert timeLimit to milliSec
this.memoryLimit = memoryLimit;
this.language = language;
this.dateTime = localDateTime;
this.averageExecutionDuration = computeTheAverageExecutionDuration(testCasesResult);
}

@ApiModelProperty(notes = "The statusResponse")
private String verdict;

@ApiModelProperty(notes = "The corresponding status code of the statusResponse")
private int statusCode;

@ApiModelProperty(notes = "An error if it occurs")
private String error;

@ApiModelProperty(notes = "The result of each test case")
private LinkedHashMap<String, TestCaseResult> testCasesResult; // Should be returned in order

@ApiModelProperty(notes = "The compilation duration")
private int compilationDuration;

@ApiModelProperty(notes = "The average execution duration")
private float averageExecutionDuration;

@ApiModelProperty(notes = "The execution time limit")
private int timeLimit;

@ApiModelProperty(notes = "The execution memory limit")
private int memoryLimit;

@ApiModelProperty(notes = "The programming language")
private Language language;

@EqualsAndHashCode.Exclude
@ApiModelProperty(notes = "The dateTime of the execution")
private LocalDateTime dateTime;

private float computeTheAverageExecutionDuration(Map<String, TestCaseResult> testCasesResult) {
float sum = 0;
for (TestCaseResult testCaseResult : testCasesResult.values()) {
if (testCaseResult.getExecutionDuration() == 0) {
continue;
}
sum += testCaseResult.getExecutionDuration();
}
return sum / testCasesResult.size();
}
}
Original file line number Diff line number Diff line change
@@ -1,104 +1,17 @@
package com.cp.compiler.contract;

import com.cp.compiler.contract.Language;
import com.cp.compiler.contract.testcases.TestCaseResult;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;

// Note: Before changing this class make sure it will not introduce a breaking change for users!!

/**
* The type Response.
* This represents the response returned to the user.
*
* @author Zakaria Maaraki
*/
@Getter
@NoArgsConstructor
@EqualsAndHashCode
@ApiModel(description = "The returned response")
public class RemoteCodeCompilerResponse {

/**
* Instantiates a new Response.
*
* @param verdict the statusResponse
* @param statusCode the status code
* @param error the error
* @param testCasesResult the test cases result
* @param compilationDuration the compilation duration
* @param timeLimit the time limit
* @param memoryLimit the memory limit
* @param language the language
* @param localDateTime the local date time
*/
public RemoteCodeCompilerResponse(String verdict,
int statusCode,
String error,
LinkedHashMap<String, TestCaseResult> testCasesResult,
int compilationDuration,
int timeLimit,
int memoryLimit,
Language language,
LocalDateTime localDateTime) {
this.verdict = verdict;
this.statusCode = statusCode;
this.error = error;
this.testCasesResult = testCasesResult;
this.compilationDuration = compilationDuration;
this.timeLimit = timeLimit * 1000; // convert timeLimit to milliSec
this.memoryLimit = memoryLimit;
this.language = language;
this.dateTime = localDateTime;
this.averageExecutionDuration = computeTheAverageExecutionDuration(testCasesResult);
}

@ApiModelProperty(notes = "The statusResponse")
private String verdict;

@ApiModelProperty(notes = "The corresponding status code of the statusResponse")
private int statusCode;

@ApiModelProperty(notes = "An error if it occurs")
private String error;

@ApiModelProperty(notes = "The result of each test case")
private LinkedHashMap<String, TestCaseResult> testCasesResult; // Should be returned in order

@ApiModelProperty(notes = "The compilation duration")
private int compilationDuration;

@ApiModelProperty(notes = "The average execution duration")
private float averageExecutionDuration;

@ApiModelProperty(notes = "The execution time limit")
private int timeLimit;

@ApiModelProperty(notes = "The execution memory limit")
private int memoryLimit;

@ApiModelProperty(notes = "The programming language")
private Language language;

@EqualsAndHashCode.Exclude
@ApiModelProperty(notes = "The dateTime of the execution")
private LocalDateTime dateTime;
@AllArgsConstructor
public class RemoteCodeCompilerResponse extends BaseRemoteCodeCompilerResponse {

private float computeTheAverageExecutionDuration(Map<String, TestCaseResult> testCasesResult) {
float sum = 0;
for (TestCaseResult testCaseResult : testCasesResult.values()) {
if (testCaseResult.getExecutionDuration() == 0) {
continue;
}
sum += testCaseResult.getExecutionDuration();
}
return sum / testCasesResult.size();
}
@ApiModelProperty(notes = "The execution response")
private RemoteCodeCompilerExecutionResponse execution;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.cp.compiler.contract.Language;
import com.cp.compiler.contract.RemoteCodeCompilerRequest;
import com.cp.compiler.contract.RemoteCodeCompilerExecutionResponse;
import com.cp.compiler.contract.RemoteCodeCompilerResponse;
import com.cp.compiler.exceptions.CompilerServerInternalException;
import com.cp.compiler.executions.Execution;
Expand Down Expand Up @@ -58,12 +59,12 @@ public CompilerController(CompilerFacade compiler) {
@ApiOperation(
value = "Json",
notes = "You should provide outputFile, inputFile (not required), source code, time limit and memory limit",
response = RemoteCodeCompilerResponse.class
response = RemoteCodeCompilerExecutionResponse.class
)
public ResponseEntity<Object> compile(@ApiParam(value = "request") @RequestBody RemoteCodeCompilerRequest request,
@RequestHeader(value = WellKnownParams.USER_ID, required = false) String userId,
@RequestHeader(value = WellKnownParams.PREFER, required = false) String prefer,
@RequestHeader(value = WellKnownParams.URL, required = false) String url)
public ResponseEntity<RemoteCodeCompilerResponse> compile(@ApiParam(value = "request") @RequestBody RemoteCodeCompilerRequest request,
@RequestHeader(value = WellKnownParams.USER_ID, required = false) String userId,
@RequestHeader(value = WellKnownParams.PREFER, required = false) String prefer,
@RequestHeader(value = WellKnownParams.URL, required = false) String url)
throws IOException {

Execution execution = ExecutionFactory.createExecution(
Expand Down Expand Up @@ -101,9 +102,9 @@ public ResponseEntity<Object> compile(@ApiParam(value = "request") @RequestBody
value = "Multipart request",
notes = "You should provide outputFile, inputFile (not required), source code, time limit and memory limit "
+ "and the language",
response = RemoteCodeCompilerResponse.class
response = RemoteCodeCompilerExecutionResponse.class
)
public ResponseEntity compile(
public ResponseEntity<RemoteCodeCompilerResponse> compile(
@ApiParam(value = "The language")
@RequestParam(value = WellKnownParams.LANGUAGE) Language language,

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.cp.compiler.controllers;

import com.cp.compiler.contract.RemoteCodeCompilerResponse;
import com.cp.compiler.contract.RemoteCodeCompilerExecutionResponse;
import com.cp.compiler.services.platform.containers.ContainerService;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -37,7 +37,7 @@ public ContainersInfoController(ContainerService containerService) {
@ApiOperation(
value = "Containers Info",
notes = "Display list of running containers",
response = RemoteCodeCompilerResponse.class
response = RemoteCodeCompilerExecutionResponse.class
)
public ResponseEntity<String> getRunningContainers() {
return ResponseEntity.ok().body(containerService.getRunningContainers());
Expand All @@ -52,7 +52,7 @@ public ResponseEntity<String> getRunningContainers() {
@ApiOperation(
value = "Images Info",
notes = "Display list of images",
response = RemoteCodeCompilerResponse.class
response = RemoteCodeCompilerExecutionResponse.class
)
public ResponseEntity<String> getImages() {
return ResponseEntity.ok().body(containerService.getImages());
Expand All @@ -67,7 +67,7 @@ public ResponseEntity<String> getImages() {
@ApiOperation(
value = "Container Stats Memory and CPU Usage",
notes = "Display Stats about running containers (Memory and CPU usage)",
response = RemoteCodeCompilerResponse.class
response = RemoteCodeCompilerExecutionResponse.class
)
public ResponseEntity<String> getRunningContainersStats() {
return ResponseEntity.ok().body(containerService.getContainersStats());
Expand All @@ -82,7 +82,7 @@ public ResponseEntity<String> getRunningContainersStats() {
@ApiOperation(
value = "Stats of Memory and CPU Usage for all containers",
notes = "Display Stats about all containers (Memory and CPU usage)",
response = RemoteCodeCompilerResponse.class
response = RemoteCodeCompilerExecutionResponse.class
)
public ResponseEntity<String> getAllContainersStats() {
return ResponseEntity.ok().body(containerService.getAllContainersStats());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.cp.compiler.controllers;

import com.cp.compiler.contract.RemoteCodeCompilerResponse;
import com.cp.compiler.contract.problems.ProblemExecution;
import com.cp.compiler.services.ux.ExecutionService;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -24,7 +25,7 @@ public ProblemExecutionController(ExecutionService executionService) {
}

@PostMapping("/execute")
public ResponseEntity<Object> execute(@RequestBody ProblemExecution problemExecution) throws IOException {
public ResponseEntity<RemoteCodeCompilerResponse> execute(@RequestBody ProblemExecution problemExecution) throws IOException {
log.info("new request, problemId = {}, language = {}, sourceCode = {}",
problemExecution.getProblemId(),
problemExecution.getLanguage(),
Expand Down
9 changes: 4 additions & 5 deletions src/main/java/com/cp/compiler/mappers/JsonMapper.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.cp.compiler.mappers;

import com.cp.compiler.contract.RemoteCodeCompilerResponse;
import com.cp.compiler.exceptions.CompilerThrottlingException;
import com.cp.compiler.executions.Execution;
import com.cp.compiler.executions.ExecutionFactory;
import com.cp.compiler.contract.RemoteCodeCompilerRequest;
import com.cp.compiler.contract.RemoteCodeCompilerResponse;
import com.cp.compiler.services.businesslogic.CompilerService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down Expand Up @@ -70,15 +70,14 @@ public static String transform(String jsonRequest, CompilerService compilerServi

try(MDC.MDCCloseable mdc = MDC.putCloseable("compiler.language", execution.getLanguage().toString())) {

ResponseEntity<Object> responseEntity = compilerService.execute(execution);
ResponseEntity<RemoteCodeCompilerResponse> responseEntity = compilerService.execute(execution);

// Throw an exception if the request has been throttled, to keep the request for retries
if (responseEntity.getStatusCode().equals(HttpStatus.TOO_MANY_REQUESTS)) {
throw new CompilerThrottlingException("The request has been throttled, maximum number of requests has been reached");
}

Object body = responseEntity.getBody();
return body instanceof RemoteCodeCompilerResponse ? JsonMapper.toJson((RemoteCodeCompilerResponse) body) : null;
// TODO: add error handling
return JsonMapper.toJson(responseEntity.getBody());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.cp.compiler.services.api;

import com.cp.compiler.contract.RemoteCodeCompilerResponse;
import com.cp.compiler.executions.Execution;
import org.springframework.http.ResponseEntity;

Expand All @@ -22,5 +23,5 @@ public interface CompilerFacade {
* @return the response entity
* @throws IOException the io exception
*/
ResponseEntity compile(Execution execution, boolean isLongRunning, String url, String userId) throws IOException;
ResponseEntity<RemoteCodeCompilerResponse> compile(Execution execution, boolean isLongRunning, String url, String userId) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.cp.compiler.services.api;

import com.cp.compiler.contract.RemoteCodeCompilerResponse;
import com.cp.compiler.exceptions.CompilerBadRequestException;
import com.cp.compiler.executions.Execution;
import com.cp.compiler.services.businesslogic.CompilerService;
Expand Down Expand Up @@ -70,8 +71,11 @@ public CompilerFacadeDefault(@Qualifier("proxy") CompilerService compilerService
}

@Override
public ResponseEntity compile(Execution execution, boolean isLongRunning, String url, String userId)
throws IOException {
public ResponseEntity<RemoteCodeCompilerResponse> compile(
Execution execution,
boolean isLongRunning,
String url,
String userId) throws IOException {

if (userId == null) {
userId = "null";
Expand Down
Loading

0 comments on commit 0f73ab1

Please sign in to comment.