Skip to content

Commit

Permalink
Expand REST operations for Submissions
Browse files Browse the repository at this point in the history
  • Loading branch information
flawmop committed Oct 16, 2024
1 parent 15b324e commit 6d4b9b1
Show file tree
Hide file tree
Showing 15 changed files with 340 additions and 89 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ testing {
}
dependencies {
implementation "com.github.dasniko:testcontainers-keycloak:${tcKeycloakVersion}"
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // JdbcTemplate, @Transactional
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.security:spring-security-test'
implementation 'org.testcontainers:junit-jupiter'
Expand Down Expand Up @@ -169,4 +170,4 @@ tasks.named('test') {

tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
package com.insilicosoft.portal.svc.submission.controller;

import java.io.IOException ;
import java.net.URI;

import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart ;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import com.insilicosoft.portal.svc.submission.SubmissionIdentifiers;
import com.insilicosoft.portal.svc.submission.exception.EntityNotAccessibleException;
import com.insilicosoft.portal.svc.submission.exception.FileProcessingException;
import com.insilicosoft.portal.svc.submission.exception.InputVerificationException;
import com.insilicosoft.portal.svc.submission.persistence.entity.Submission;
import com.insilicosoft.portal.svc.submission.service.InputProcessorService;
import com.insilicosoft.portal.svc.submission.service.SubmissionService;

import io.micrometer.core.annotation.Timed;

/**
* Simulation controller
* Submission controller
*
* @author geoff
*/
@Controller
@RestController
@RequestMapping(SubmissionIdentifiers.REQUEST_MAPPING_SUBMISSION)
public class SubmissionController {

Expand All @@ -46,10 +54,18 @@ public SubmissionController(final InputProcessorService inputProcessorService,
this.submissionService = submissionService;
}

@GetMapping()
/**
* Retrieve a {@link Submission}.
*
* @param submissionId Submission identifier.
* @return Found submission.
* @throws EntityNotAccessibleException If not found or not retrievable due to security.
*/
@GetMapping(value = "/{id}")
@Timed(value = "submission.get", description = "GET request")
public ResponseEntity<String> get() {
return ResponseEntity.ok(inputProcessorService.get());
public Submission get(final @PathVariable(name = "id") long submissionId)
throws EntityNotAccessibleException {
return submissionService.retrieve(submissionId);
}

/**
Expand All @@ -58,14 +74,15 @@ public ResponseEntity<String> get() {
* @param file File being uploaded.
* @return Response entity.
* @throws FileProcessingException If problems processing file.
* @throws InputVerificationException If supplied input is invalid.
*/
@PostMapping(value = SubmissionIdentifiers.REQUEST_MAPPING_SIMULATION)
@Timed(value = "submission.simulation.post", description = "Submit Simulation POST Multipart request")
public ResponseEntity<String> createSimulation(final @RequestPart(required=false,
value=SubmissionIdentifiers.PARAM_NAME_SIMULATION_FILE)
MultipartFile file)
throws FileProcessingException,
InputVerificationException {
// 'required=false' to enable manual checking for null file
public ResponseEntity<Void> createSimulation(final @RequestPart(required=false,
value=SubmissionIdentifiers.PARAM_NAME_SIMULATION_FILE)
MultipartFile file)
throws FileProcessingException, InputVerificationException {

if (file == null) {
final String message = "No Multipart file! Did you supply the parameter '" + SubmissionIdentifiers.PARAM_NAME_SIMULATION_FILE + "' in the POST request?";
Expand All @@ -85,11 +102,29 @@ public ResponseEntity<String> createSimulation(final @RequestPart(required=false
throw new FileProcessingException(e.getMessage());
}

final long submissionId = submissionService.submit();
final Submission submission = submissionService.create();
final Long submissionId = submission.getEntityId();

inputProcessorService.process(submissionId, fileByteArray);

return ResponseEntity.ok(String.valueOf(submissionId));
final URI location = ServletUriComponentsBuilder.fromCurrentRequestUri()
.path("/{submissionId}")
.buildAndExpand(submissionId)
.toUri();

return ResponseEntity.created(location).build();
}

/**
* Delete a {@link Submission}.
*
* @param id Identifier of submission to delete.
* @throws EntityNotAccessibleException If not found or not retrievable due to security.
*/
@DeleteMapping(value = "/{id}")
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@Timed(value = "submission.delete", description = "DELETE request")
public void delete(final @PathVariable(name = "id") long id) throws EntityNotAccessibleException {
submissionService.delete(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;

import com.insilicosoft.portal.svc.submission.exception.EntityNotAccessibleException;
import com.insilicosoft.portal.svc.submission.exception.FileProcessingException;
import com.insilicosoft.portal.svc.submission.exception.InputVerificationException;

Expand All @@ -18,6 +19,17 @@
@RestControllerAdvice
public class ControllerAdvice {

/**
* Something we're going to handle.
*
* @param e Entity not accessible exception.
* @return Response entity.
*/
@ExceptionHandler(EntityNotAccessibleException.class)
public ResponseEntity<String> handleEntityNotAccessible(EntityNotAccessibleException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}

/**
* Something we're going to handle.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.insilicosoft.portal.svc.submission.exception;

/**
* Exception thrown when entity not found or not visible to user.
*/
public class EntityNotAccessibleException extends Exception {

private static final long serialVersionUID = 6311364080916164926L;

private static final String message = "%s with identifier '%s' was not found";

/**
* Initialising constructor.
*
* @param entity Entity name.
* @param id Entity identifier.
*/
public EntityNotAccessibleException(final String entity, final String id) {
super(String.format(message, entity, id));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/
public class FileProcessingException extends Exception {

private static final long serialVersionUID = - 8135834798094531867L ;
private static final long serialVersionUID = -8135834798094531867L;

/**
* Initialising constructor.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.FetchType;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
Expand Down Expand Up @@ -61,13 +62,17 @@ public class Simulation {
@Column(nullable = false)
private BigDecimal pacingMaxTime;

@ElementCollection
@CollectionTable(name = "simulation_plasmapoints", joinColumns = @JoinColumn(name = "entityId"))
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "simulation_plasmapoints",
foreignKey = @ForeignKey(name = "simulation_fk"),
joinColumns = @JoinColumn(name = "entityId"))
@Column(nullable = false)
private List<BigDecimal> plasmaPoints = new ArrayList<>();

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "simulation_message", joinColumns = @JoinColumn(name = "entityId"))
@CollectionTable(name = "simulation_message",
foreignKey = @ForeignKey(name = "simulation_fk"),
joinColumns = @JoinColumn(name = "entityId"))
@Column(nullable = false)
private Set<Message> messages = new HashSet<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
Expand All @@ -44,7 +45,10 @@ public class Submission {
private State state;

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "submission_message", joinColumns = @JoinColumn(name = "entityId"))
@CollectionTable(name = "submission_message",
foreignKey = @ForeignKey(name = "simulation_fk"),
joinColumns = @JoinColumn(name = "entityId"))
@Column(nullable = false)
private Set<Message> messages = new HashSet<>();

// See JPA auditing
Expand Down Expand Up @@ -109,12 +113,21 @@ public Long getEntityId() {
return entityId;
}

/**
* Retrieve the Submission state.
*
* @return the state
*/
public State getState() {
return state;
}

// Boilerplate implementations

@Override
public String toString() {
return "Submission [entityId=" + entityId + ", state=" + state + ", createdDate=" + createdDate + ", createdBy="
+ createdBy + "]";
return "Submission [entityId=" + entityId + ", state=" + state + ", messages=" + messages + ", createdDate="
+ createdDate + ", createdBy=" + createdBy + "]";
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.insilicosoft.portal.svc.submission.persistence.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

import com.insilicosoft.portal.svc.submission.persistence.entity.Simulation;

Expand All @@ -11,4 +13,8 @@
*/
public interface SimulationRepository extends JpaRepository<Simulation, Long> {

@Modifying
@Query("DELETE FROM Simulation WHERE submissionId = ?1")
void deleteAllBySubmissionId(long submissionId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
*/
public interface InputProcessorService {

// TODO Remove
String get();

/**
* Process a file.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,6 @@ public InputProcessorServiceImpl(final SimulationRepository simulationRepository
this.submissionService = submissionService;
}

@Override
public String get() {
return "All good from SubmissionController->InputProcessorService!!";
}

@Override
public void process(final long submissionId, final byte[] file) throws FileProcessingException,
InputVerificationException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,32 @@
import java.util.Map;
import java.util.Set;

import com.insilicosoft.portal.svc.submission.exception.EntityNotAccessibleException;
import com.insilicosoft.portal.svc.submission.persistence.entity.Message;
import com.insilicosoft.portal.svc.submission.persistence.entity.Submission;

/**
* User {@link Submission} service.
* User {@link Submission} service.
*
* @author geoff
*/
public interface SubmissionService {

/**
* Creates a new {@link Submission}.
*
* @return Submission.
*/
Submission create();

/**
* Delete the {@link Submission} (and all linked entities!).
*
* @param submissionId Submission identifier.
* @throws EntityNotAccessibleException If identified Submission not accessible.
*/
void delete(long submissionId) throws EntityNotAccessibleException;

/**
* Reject the {@link Submission} due to file processing problems.
*
Expand All @@ -28,10 +46,12 @@ public interface SubmissionService {
void rejectOnInvalidInput(long submissionId, Map<String, Set<Message>> problems);

/**
* {@link Submission} of some kind.
* Retrieve the {@link Submission} identified by the {@literal submissionId}.
*
* @return Submission identifier.
* @param submissionId Submission identifier.
* @return Submission
* @throws EntityNotAccessibleException If identified Submission not accessible.
*/
long submit();
Submission retrieve(long submissionId) throws EntityNotAccessibleException;

}
Loading

0 comments on commit 6d4b9b1

Please sign in to comment.