org.projectlombok
diff --git a/src/main/java/it/cnr/isti/workflow/manager/configurations/OpenApiConfig.java b/src/main/java/it/cnr/isti/workflow/manager/configurations/OpenApiConfig.java
new file mode 100644
index 0000000..8f46877
--- /dev/null
+++ b/src/main/java/it/cnr/isti/workflow/manager/configurations/OpenApiConfig.java
@@ -0,0 +1,30 @@
+package it.cnr.isti.workflow.manager.configurations;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.swagger.v3.oas.models.security.SecurityScheme.Type;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class OpenApiConfig {
+
+ @Bean
+ public OpenAPI customOpenAPI() {
+ final String securitySchemeName = "bearerAuth";
+
+ return new OpenAPI()
+ .info(new Info().title("API Docs").version("v1"))
+ .components(new io.swagger.v3.oas.models.Components()
+ .addSecuritySchemes(securitySchemeName,
+ new SecurityScheme()
+ .name(securitySchemeName)
+ .type(Type.HTTP)
+ .scheme("bearer")
+ .bearerFormat("JWT")
+ )
+ );
+ }
+}
+
diff --git a/src/main/java/it/cnr/isti/workflow/manager/configurations/SecurityConfig.java b/src/main/java/it/cnr/isti/workflow/manager/configurations/SecurityConfig.java
index 4cd6eed..6144282 100644
--- a/src/main/java/it/cnr/isti/workflow/manager/configurations/SecurityConfig.java
+++ b/src/main/java/it/cnr/isti/workflow/manager/configurations/SecurityConfig.java
@@ -14,7 +14,6 @@ import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@@ -26,17 +25,19 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
- .cors(Customizer.withDefaults())
- .csrf(csrf -> csrf.disable())
- .authorizeHttpRequests(auth -> auth
- .requestMatchers("/auth/**").permitAll()
- .requestMatchers(HttpMethod.GET,"/health").permitAll()
- .requestMatchers(HttpMethod.GET,"/types/nodes/**").permitAll()
- .anyRequest().authenticated()
- )
- .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
- .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
- .build();
+ .cors(Customizer.withDefaults())
+ .csrf(csrf -> csrf.disable())
+ .authorizeHttpRequests(auth -> auth
+ .requestMatchers("/auth/**").permitAll()
+ //.requestMatchers(HttpMethod.GET, "/health").permitAll()
+ .requestMatchers(HttpMethod.GET, "/types/nodes/**").permitAll()
+ .requestMatchers("/swagger-ui.html").permitAll()
+ .requestMatchers("/swagger-ui/**").permitAll()
+ .requestMatchers("/v3/api-docs/**").permitAll()
+ .anyRequest().authenticated())
+ .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+ .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
+ .build();
}
@Bean
diff --git a/src/main/java/it/cnr/isti/workflow/manager/controllers/ExecutionController.java b/src/main/java/it/cnr/isti/workflow/manager/controllers/ExecutionController.java
index e8780ba..6b5597b 100644
--- a/src/main/java/it/cnr/isti/workflow/manager/controllers/ExecutionController.java
+++ b/src/main/java/it/cnr/isti/workflow/manager/controllers/ExecutionController.java
@@ -8,14 +8,17 @@ import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.server.WebServerException;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import it.cnr.isti.workflow.manager.exceptions.WebException;
import it.cnr.isti.workflow.manager.executors.ExecutionObject;
import it.cnr.isti.workflow.manager.model.ExecutionContext;
import it.cnr.isti.workflow.manager.model.flows.Flow;
@@ -28,6 +31,44 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
+/**
+ * The ExecutionController class provides RESTful endpoints for managing
+ * execution objects and their associated contexts and inputs. It allows
+ * clients to create, retrieve, update, and delete execution objects, as
+ * well as prepare inputs for executions.
+ *
+ * Endpoints include:
+ *
+ * - Creating a new execution for a given flow
+ * - Retrieving all executions or a specific execution by ID
+ * - Retrieving all execution contexts
+ * - Starting an execution
+ * - Preparing string or file inputs for an execution
+ * - Deleting an execution
+ *
+ *
+ * Exception handling is provided for cases where a requested flow or
+ * execution is not found, returning appropriate HTTP status codes.
+ *
+ *
Security is enforced using the "bearerAuth" security requirement.
+ *
+ *
Dependencies:
+ *
+ * - {@link FlowRepository} for accessing flow data
+ * - {@link ExecutionService} for managing execution logic
+ *
+ *
+ * Logging is performed using SLF4J to provide insights into the operations
+ * performed by the controller.
+ *
+ *
Annotations:
+ *
+ * - {@code @RestController} to define this class as a REST controller
+ * - {@code @RequestMapping("/executions")} to map requests to the "/executions" path
+ * - {@code @SecurityRequirement(name = "bearerAuth")} to enforce security
+ *
+ */
+@SecurityRequirement(name = "bearerAuth")
@RestController
@RequestMapping("/executions")
public class ExecutionController {
@@ -40,6 +81,16 @@ public class ExecutionController {
@Autowired
ExecutionService executionService;
+
+ /**
+ * Creates a new execution object for the specified flow.
+ *
+ * @param flowId the ID of the flow for which the execution is to be created
+ * @return the created {@link ExecutionObject}
+ * @throws IllegalArgumentException if the flow with the specified ID is not found
+ * @throws WebServerException if an error occurs while creating the execution
+ */
+ @Operation(summary = "Creates an execution", description = "Creates a new execution object for the specified flow.")
@PostMapping()
public ExecutionObject create(@RequestBody String flowId) {
logger.info("Creating execution for flow {}", flowId);
@@ -50,39 +101,104 @@ public class ExecutionController {
return eo;
} catch (Throwable e) {
logger.error("Error creating execution for flow {}", flowId, e);
- throw new WebServerException("Error while creating execution", e);
+ throw new WebException(HttpStatus.INTERNAL_SERVER_ERROR,"Error while creating execution");
}
}
+ /**
+ * Retrieves a list of all executions.
+ *
+ * @return a list of {@link ExecutionObject} representing all executions.
+ */
+ @Operation(summary = "Retrieves executions", description = "Retrieves a list of all executions")
@GetMapping()
public List getAll() {
return executionService.getAllExecutions();
}
+
+
+ /**
+ * Retrieves all execution contexts.
+ *
+ * @return a map of execution IDs to their corresponding {@link ExecutionContext}
+ */
+ @Operation(summary = "Retrieves contexts", description = "Retrieves all execution contexts")
@GetMapping(path = "contexts")
public Map getAllContexts() {
return executionService.getAllExecutions().stream().collect(Collectors.toMap(ExecutionObject::getId, ExecutionObject::getContext));
}
@GetMapping(path = "{id}")
+ /**
+ * Retrieves a specific execution by its ID.
+ *
+ * @param id the ID of the execution to retrieve
+ * @return the {@link ExecutionObject} with the specified ID
+ * @throws IllegalArgumentException if the execution with the specified ID is not found
+ */
+ @Operation(summary = "Retrieves an execution", description = "Retrieves a specific execution by its ID")
public ExecutionObject get(@PathVariable String id) {
return executionService.getExecution(id);
}
+ /**
+ * Deletes an execution with the specified ID.
+ *
+ * @param id the unique identifier of the execution to be deleted
+ * @return a ResponseEntity indicating the result of the operation
+ */
+ @DeleteMapping(path = "{id}")
+ @Operation(summary = "Deletes an execution", description = "Deletes an execution with the specified ID")
+ public ResponseEntity> delete(@PathVariable String id) {
+ executionService.removeExecution(id);
+ return ResponseEntity.ok().build();
+ }
+
+ /**
+ * Starts the execution of a workflow with the given ID.
+ *
+ * @param id the unique identifier of the workflow to start
+ * @return the {@link ExecutionObject} representing the started execution
+ */
@PutMapping(path = "{id}/start")
+ @Operation(summary = "Starts an execution", description = "Starts the execution of a workflow with the given ID")
public ExecutionObject start(@PathVariable String id) {
return executionService.startExecution(id);
}
+
+ /**
+ * Prepares the input for an execution by associating a given input string
+ * with a specific input name and execution ID.
+ *
+ * @param input The input string to be prepared and associated.
+ * @param inputName The name of the input to be associated with the execution.
+ * @param id The unique identifier of the execution.
+ * @return An {@link ExecutionObject} representing the updated execution state
+ * after preparing the input.
+ */
@PutMapping(path = "{id}/input/{inputName}")
+ @Operation(summary = "Prepares string inputs", description = "Prepares the input for an execution by associating a given input string with a specific input name and execution ID.")
public ExecutionObject prepareStringInputs(@RequestBody String input, @PathVariable String inputName,
@PathVariable String id) {
return executionService.prepareInput(id, inputName, input);
}
+ /**
+ * Prepares file inputs for a specific execution by uploading a file and associating it
+ * with the given input name and execution ID.
+ *
+ * @param file The multipart file to be uploaded and processed.
+ * @param inputName The name of the input to associate the file with.
+ * @param id The ID of the execution to which the input belongs.
+ * @return An {@link ExecutionObject} representing the updated execution state after
+ * preparing the input.
+ * @throws WebServerException If an error occurs while creating or transferring the file.
+ */
@PutMapping(path = "{id}/input/{inputName}", consumes = "multipart/form-data")
- @ResponseBody
+ @Operation(summary = "Prepares file inputs", description = "Prepares file inputs for a specific execution by uploading a file and associating it with the given input name and execution ID.")
public ExecutionObject prepareFileInputs(@RequestParam("file") MultipartFile file, @PathVariable String inputName,
@PathVariable String id) {
try {
@@ -95,8 +211,4 @@ public class ExecutionController {
}
- @ExceptionHandler(IllegalArgumentException.class)
- public ResponseEntity> executionNotFound(IllegalArgumentException exc) {
- return ResponseEntity.notFound().build();
- }
}
diff --git a/src/main/java/it/cnr/isti/workflow/manager/controllers/FlowsController.java b/src/main/java/it/cnr/isti/workflow/manager/controllers/FlowsController.java
index 2886d98..854d7a4 100644
--- a/src/main/java/it/cnr/isti/workflow/manager/controllers/FlowsController.java
+++ b/src/main/java/it/cnr/isti/workflow/manager/controllers/FlowsController.java
@@ -10,12 +10,12 @@ import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import it.cnr.isti.workflow.manager.exceptions.WebException;
import it.cnr.isti.workflow.manager.model.auth.LoginEntity;
import it.cnr.isti.workflow.manager.model.flows.Flow;
@@ -29,7 +29,32 @@ import org.springframework.web.bind.annotation.GetMapping;
-
+/**
+ * Controller for managing flows.
+ *
+ * This controller provides endpoints for creating, updating, retrieving, and listing flows.
+ * It enforces security requirements and ensures that users can only access or modify flows
+ * they have created or that are marked as public.
+ *
+ * Endpoints:
+ * - POST /flows: Create a new flow.
+ * - PUT /flows/{id}: Update an existing flow.
+ * - GET /flows: Retrieve all flows created by the user or public flows.
+ * - GET /flows/{id}: Retrieve a specific flow by its ID.
+ *
+ * Security:
+ * - Requires bearer authentication.
+ * - Users can only modify or retrieve flows they created unless the flow is public.
+ *
+ * Dependencies:
+ * - FlowRepository: Repository for accessing and managing flow data.
+ * - Logger: Used for logging flow creation and updates.
+ *
+ * Exceptions:
+ * - WebException: Thrown for various HTTP error scenarios, such as invalid input,
+ * unauthorized access, or resource not found.
+ */
+@SecurityRequirement(name = "bearerAuth")
@RestController
@RequestMapping("/flows")
public class FlowsController {
@@ -40,7 +65,20 @@ public class FlowsController {
FlowRepository flowRepository;
+ /**
+ * Creates a new flow.
+ *
+ * This method handles HTTP POST requests with a JSON payload to create a new flow.
+ * It validates that the flow ID is null (as it must be generated during creation),
+ * sets the creator's username, and saves the flow to the repository.
+ *
+ * @param flow The flow object to be created, provided in the request body.
+ * @param userDetails The authenticated user's details, used to set the creator of the flow.
+ * @return The saved flow object with its generated ID and other persisted details.
+ * @throws WebException If the flow ID is not null, indicating an invalid creation request.
+ */
@PostMapping(consumes = "application/json")
+ @Operation(summary = "Create a new flow", description = "Creates a new flow in the system.")
public Flow createFlow(@RequestBody Flow flow, @AuthenticationPrincipal LoginEntity userDetails) {
//validateFlow(flow);
if (flow.getId() != null)
@@ -52,7 +90,19 @@ public class FlowsController {
return savedFlow;
}
+ /**
+ * Updates and saves an existing Flow entity.
+ *
+ * @param id The ID of the Flow to be updated. Must match the ID of the provided Flow object.
+ * @param flow The Flow object containing the updated data.
+ * @param userDetails The authenticated user's details, used to verify ownership of the Flow.
+ * @return The updated and saved Flow object.
+ * @throws WebException If the provided Flow ID does not match the path variable ID (BAD_REQUEST),
+ * if the Flow is not found (NOT_FOUND),
+ * or if the authenticated user is not the creator of the Flow (FORBIDDEN).
+ */
@PutMapping(path = "{id}", consumes = "application/json")
+ @Operation(summary = "Update an existing flow", description = "Updates an existing flow in the system.")
public Flow saveFlow(@PathVariable String id, @RequestBody Flow flow, @AuthenticationPrincipal LoginEntity userDetails) {
//validateFlow(flow);
if (!id.equals(flow.getId()))
@@ -62,12 +112,26 @@ public class FlowsController {
if (!savedFlow.getCreatedBy().equals(userDetails.getUsername()))
throw new WebException(HttpStatus.FORBIDDEN, "Flow not created by user");
- savedFlow = flowRepository.save(savedFlow);
+ savedFlow = flowRepository.save(flow);
logger.info("Flow saved: {} ",savedFlow.getId());
return savedFlow;
}
+ /**
+ * Retrieves all flows created by the authenticated user or public flows.
+ *
+ * This endpoint is mapped to a GET request and provides a list of flows
+ * that are either created by the currently authenticated user or are marked
+ * as public. The method uses the user's authentication details to filter
+ * the flows accordingly.
+ *
+ * @param userDetails The authentication principal containing the details of
+ * the currently authenticated user.
+ * @return A list of {@link Flow} objects representing the flows accessible
+ * to the authenticated user.
+ */
@GetMapping()
+ @Operation(summary = "Get all flows", description = "Retrieves all flows created by the user or public flows.")
public List getAllFlows(@AuthenticationPrincipal LoginEntity userDetails) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
System.out.println("Authentication: " + auth);
@@ -77,6 +141,21 @@ public class FlowsController {
}
@GetMapping("{id}")
+ @Operation(summary = "Get a flow by ID", description = "Retrieves a specific flow by its ID.")
+ /**
+ * Retrieves a specific flow by its ID.
+ *
+ * This endpoint is mapped to a GET request and allows the retrieval of
+ * a flow based on its unique identifier. The method checks if the flow
+ * exists and whether the authenticated user has permission to access it.
+ *
+ * @param id The ID of the flow to be retrieved.
+ * @param userDetails The authentication principal containing the details of
+ * the currently authenticated user.
+ * @return The {@link Flow} object representing the requested flow.
+ * @throws WebException If the flow is not found (NOT_FOUND) or if the user
+ * does not have permission to access it (FORBIDDEN).
+ */
public Flow getFlow(@PathVariable String id, @AuthenticationPrincipal LoginEntity userDetails) {
Flow flowEntity = flowRepository.findById(id).orElseThrow(() -> new WebException(HttpStatus.NOT_FOUND,"Flow not found"));
if (!flowEntity.getCreatedBy().equals(userDetails.getUsername()) && !flowEntity.isPublic())
diff --git a/src/main/java/it/cnr/isti/workflow/manager/controllers/NodeDefinitionController.java b/src/main/java/it/cnr/isti/workflow/manager/controllers/NodeDefinitionController.java
index afb0634..6af69b2 100644
--- a/src/main/java/it/cnr/isti/workflow/manager/controllers/NodeDefinitionController.java
+++ b/src/main/java/it/cnr/isti/workflow/manager/controllers/NodeDefinitionController.java
@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-import it.cnr.isti.workflow.manager.exceptions.WebException;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import it.cnr.isti.workflow.manager.executors.Executor;
import it.cnr.isti.workflow.manager.model.ExecutorDescriptor;
import it.cnr.isti.workflow.manager.model.types.NodeDefinition;
@@ -29,46 +29,32 @@ public class NodeDefinitionController {
@Autowired
private List executors;
+ @SecurityRequirement(name = "bearerAuth")
@GetMapping("/nodes")
public List getNodes() {
- try {
- return (List) repository.findAll();
- } catch (Throwable e) {
- logger.error("Error retrieving nodes", e);
- throw new RuntimeException("Error retrieving nodes", e);
- }
+ return (List) repository.findAll();
+
}
+
@GetMapping("/nodes/types")
public List getStoredNodeTypes() {
- try {
- return repository.getUsedTypes();
- } catch (Throwable e) {
- logger.error("Error retrieving stored types", e);
- throw new WebException(HttpStatus.INTERNAL_SERVER_ERROR, "Error retrieving stored types");
- }
+ return repository.getUsedTypes();
+
}
@GetMapping("/nodes/categories")
public List getStoredNodeCategories() {
- try {
- return repository.getCategories();
- } catch (Throwable e) {
- logger.error("Error retrieving stored categories", e);
- throw new WebException(HttpStatus.INTERNAL_SERVER_ERROR, "Error retrieving stored categories");
- }
+ return repository.getCategories();
}
+ @SecurityRequirement(name = "bearerAuth")
@PostMapping("/nodes")
void addNode(@RequestBody NodeDefinition node) {
- try {
- repository.save(node);
- } catch (Exception e) {
- logger.error("Error saving node", e);
- throw new RuntimeException("Error saving node", e);
- }
+ repository.save(node);
}
+ @SecurityRequirement(name = "bearerAuth")
@GetMapping("/executors")
public List getAvailableExecutors() {
return executors.stream().map(entry -> entry.getDescriptor(null)).toList();
diff --git a/src/main/java/it/cnr/isti/workflow/manager/exceptions/GlobalExceptionHandler.java b/src/main/java/it/cnr/isti/workflow/manager/exceptions/GlobalExceptionHandler.java
index ecc4a8c..19d0e1d 100644
--- a/src/main/java/it/cnr/isti/workflow/manager/exceptions/GlobalExceptionHandler.java
+++ b/src/main/java/it/cnr/isti/workflow/manager/exceptions/GlobalExceptionHandler.java
@@ -1,16 +1,23 @@
package it.cnr.isti.workflow.manager.exceptions;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
@ControllerAdvice
public class GlobalExceptionHandler {
- @ExceptionHandler(WebException.class)
- public ResponseEntity handleWebException(WebException ex) {
+ @ExceptionHandler(ResourceNotFoundException.class)
+ public ResponseEntity handleNotFound(ResourceNotFoundException ex, WebRequest request) {
+ return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
+ }
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleGenericException(Exception ex) {
return ResponseEntity
- .status(ex.getStatus())
- .body(ex.getMessage());
+ .status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body("An unexpected error occurred: " + ex.getMessage());
}
}
diff --git a/src/main/java/it/cnr/isti/workflow/manager/exceptions/InvalidStateException.java b/src/main/java/it/cnr/isti/workflow/manager/exceptions/InvalidStateException.java
new file mode 100644
index 0000000..ff86064
--- /dev/null
+++ b/src/main/java/it/cnr/isti/workflow/manager/exceptions/InvalidStateException.java
@@ -0,0 +1,24 @@
+package it.cnr.isti.workflow.manager.exceptions;
+
+public class InvalidStateException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public InvalidStateException(String message) {
+ super(message);
+ }
+
+ public InvalidStateException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidStateException(Throwable cause) {
+ super(cause);
+ }
+
+ public InvalidStateException(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+}
diff --git a/src/main/java/it/cnr/isti/workflow/manager/exceptions/ResourceNotFoundException.java b/src/main/java/it/cnr/isti/workflow/manager/exceptions/ResourceNotFoundException.java
new file mode 100644
index 0000000..cedbeec
--- /dev/null
+++ b/src/main/java/it/cnr/isti/workflow/manager/exceptions/ResourceNotFoundException.java
@@ -0,0 +1,14 @@
+package it.cnr.isti.workflow.manager.exceptions;
+
+public class ResourceNotFoundException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public ResourceNotFoundException(String message) {
+ super(message);
+ }
+
+ public ResourceNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/src/main/java/it/cnr/isti/workflow/manager/exceptions/WebException.java b/src/main/java/it/cnr/isti/workflow/manager/exceptions/WebException.java
index 3670a27..b30f810 100644
--- a/src/main/java/it/cnr/isti/workflow/manager/exceptions/WebException.java
+++ b/src/main/java/it/cnr/isti/workflow/manager/exceptions/WebException.java
@@ -13,4 +13,4 @@ public class WebException extends RuntimeException {
public HttpStatus getStatus() {
return status;
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/it/cnr/isti/workflow/manager/model/ExecutionContext.java b/src/main/java/it/cnr/isti/workflow/manager/model/ExecutionContext.java
index df5ea1d..51dcd48 100644
--- a/src/main/java/it/cnr/isti/workflow/manager/model/ExecutionContext.java
+++ b/src/main/java/it/cnr/isti/workflow/manager/model/ExecutionContext.java
@@ -14,22 +14,29 @@ import lombok.Setter;
public class ExecutionContext {
public enum Status {
- CREATED(true),
- INITIALIZING(true),
- READY(true),
- RUNNING(false),
- SUCCESS(false),
- ERROR(false);
+ CREATED(true, false),
+ INITIALIZING(true, false),
+ READY(true, false),
+ RUNNING(false, false),
+ SUCCESS(false, true),
+ ERROR(false, true);
private boolean initState;
- Status(boolean initState) {
+ private boolean finalState;
+
+ Status(boolean initState, boolean finalState) {
this.initState = initState;
+ this.finalState = finalState;
}
public boolean isInitState() {
return initState;
}
+
+ public boolean isFinaltate() {
+ return finalState;
+ }
}
Map inputs = new HashMap<>();
diff --git a/src/main/java/it/cnr/isti/workflow/manager/services/ExecutionService.java b/src/main/java/it/cnr/isti/workflow/manager/services/ExecutionService.java
index f4143d9..1ac3adb 100644
--- a/src/main/java/it/cnr/isti/workflow/manager/services/ExecutionService.java
+++ b/src/main/java/it/cnr/isti/workflow/manager/services/ExecutionService.java
@@ -6,7 +6,6 @@ import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-
import it.cnr.isti.workflow.manager.executors.ExecutionObject;
import it.cnr.isti.workflow.manager.model.ExecutionContext.Status;
import it.cnr.isti.workflow.manager.model.flows.Flow;
@@ -26,7 +25,10 @@ public class ExecutionService {
}
public ExecutionObject getExecution(String id) {
- return executions.get(id);
+ ExecutionObject toReturn = executions.get(id);
+ if (toReturn == null)
+ throw new IllegalArgumentException("Execution with id " + id + " not found");
+ return toReturn;
}
public List getAllExecutions() {
@@ -34,14 +36,16 @@ public class ExecutionService {
}
public void removeExecution(String id) {
+ if (!executions.containsKey(id))
+ throw new IllegalArgumentException("Execution with id " + id + " not found");
+ if (executions.get(id).getContext().getStatus() == Status.RUNNING)
+ throw new IllegalStateException("Execution with id "+id+" is still running");
executions.remove(id);
}
public ExecutionObject prepareInput(String id, String key, Object input) {
ExecutionObject eo = getExecution(id);
- if (eo == null)
- throw new IllegalArgumentException("Execution with id " + id + " not found");
-
+
if (!eo.getContext().getStatus().isInitState()) {
throw new IllegalStateException("Execution with id " + id
+ " is not in initialization status (CURRENT STATUS is " + eo.getContext().getStatus() + ")");
@@ -58,8 +62,7 @@ public class ExecutionService {
public ExecutionObject startExecution(String id) {
ExecutionObject eo = getExecution(id);
- if (eo == null)
- throw new IllegalArgumentException("Execution with id " + id + " not found");
+
if (eo.getContext().getStatus() != Status.READY) {
throw new IllegalStateException("Execution with id " + id + " is not in READY status (CURRENT STATUS is "
+ eo.getContext().getStatus() + ")");