From 3355738e5a89eaa9ad8e52397e3c822216db0909 Mon Sep 17 00:00:00 2001 From: Francisco Javier Tirado Sarti Date: Thu, 30 May 2024 12:12:40 +0200 Subject: [PATCH 1/9] [Fix_#359] Migration to 0.10 DSL Signed-off-by: Francisco Javier Tirado Sarti [Fix #359] Generating not referenced Pojos Signed-off-by: Francisco Javier Tirado Sarti --- pom.xml | 69 ++++++++++++--------------------------------------------- 1 file changed, 14 insertions(+), 55 deletions(-) diff --git a/pom.xml b/pom.xml index d661d4d3..a0e56216 100644 --- a/pom.xml +++ b/pom.xml @@ -38,10 +38,7 @@ api - spi - validation - diagram - utils + custom-generator @@ -49,7 +46,7 @@ ${java.version} ${java.version} UTF-8 - 3.6.2 + 3.9.7 3.2.0 @@ -62,8 +59,13 @@ 3.2.4 3.4.1 ${java.version} +<<<<<<< Upstream, based on main 1.1.2 3.7.0 +======= + 1.2.1 + 3.6.3 +>>>>>>> 008f450 [Fix_#359] Migration to 0.10 DSL 3.0.1 3.3.1 3.2.5 @@ -73,18 +75,13 @@ 1.5.6 2.17.1 1.4.0 - 3.14.0 - 0.17.0 - 1.3 3.1.0 1.5.0 3.26.0 5.10.2 5.12.0 2.0.13 - 8059 - 3.1.2.RELEASE - + true @@ -117,11 +114,6 @@ slf4j-api ${version.org.slf4j} - - org.slf4j - jcl-over-slf4j - ${version.org.slf4j} - com.fasterxml.jackson.core jackson-core @@ -136,44 +128,23 @@ com.networknt json-schema-validator ${version.com.networknt} - - - org.apache.commons - commons-lang3 - - com.fasterxml.jackson.dataformat jackson-dataformat-yaml ${version.com.fasterxml.jackson} + + org.jsonschema2pojo + jsonschema2pojo-core + ${version.jsonschema2pojo-maven-plugin} + jakarta.validation jakarta.validation-api ${version.jakarta.validation} - - org.apache.commons - commons-lang3 - ${version.commons.lang} - - - org.thymeleaf - thymeleaf - ${version.thymeleaf} - - - net.sourceforge.plantuml - plantuml - ${version.plantuml} - - - guru.nidi - graphviz-java - ${version.graphviz} - - + org.junit.jupiter @@ -211,18 +182,6 @@ ${version.org.assertj} test - - org.hamcrest - hamcrest-library - ${version.hamcrest} - test - - - org.skyscreamer - jsonassert - ${version.jsonassert} - test - From 1d080a82f0850b0eaebe90ece8ee535ac5e3008e Mon Sep 17 00:00:00 2001 From: Francisco Javier Tirado Sarti Date: Thu, 13 Jun 2024 19:50:00 +0200 Subject: [PATCH 2/9] [Fix_#359] Rebase Signed-off-by: Francisco Javier Tirado Sarti --- README.md | 342 +------ api/.gitignore | 3 +- api/pom.xml | 24 +- .../api/ObjectMapperFactory.java | 46 + ...MapperFactory.java => WorkflowFormat.java} | 25 +- .../api/WorkflowReader.java | 58 ++ .../api/WorkflowWriter.java | 49 + .../AuthDefinitionDeserializer.java | 80 -- .../api/deserializers/AuthDeserializer.java | 88 -- .../deserializers/ConstantsDeserializer.java | 81 -- .../deserializers/ContinueAsDeserializer.java | 83 -- .../api/deserializers/CronDeserializer.java | 68 -- .../DataInputSchemaDeserializer.java | 65 -- .../DefaultStateTypeDeserializer.java | 70 -- .../EndDefinitionDeserializer.java | 94 -- .../api/deserializers/ErrorsDeserializer.java | 88 -- .../EventDefinitionKindDeserializer.java | 68 -- .../api/deserializers/EventsDeserializer.java | 89 -- .../deserializers/ExtensionDeserializer.java | 81 -- .../FunctionDefinitionTypeDeserializer.java | 69 -- .../FunctionRefDeserializer.java | 80 -- .../deserializers/FunctionsDeserializer.java | 90 -- .../OnEventsActionModeDeserializer.java | 69 -- .../OperationStateActionModeDeserializer.java | 71 -- ...rallelStateCompletionTypeDeserializer.java | 71 -- .../deserializers/RetriesDeserializer.java | 88 -- .../deserializers/ScheduleDeserializer.java | 75 -- .../deserializers/SecretsDeserializer.java | 85 -- .../StartDefinitionDeserializer.java | 72 -- .../api/deserializers/StateDeserializer.java | 95 -- .../StateExecTimeoutDeserializer.java | 70 -- .../StringValueDeserializer.java | 67 -- .../deserializers/SubFlowRefDeserializer.java | 77 -- .../deserializers/TransitionDeserializer.java | 80 -- .../api/interfaces/Extension.java | 20 - .../api/interfaces/State.java | 48 - .../api/interfaces/SwitchCondition.java | 18 - .../api/interfaces/WorkflowDiagram.java | 30 - .../interfaces/WorkflowPropertySource.java | 25 - .../api/interfaces/WorkflowValidator.java | 35 - .../api/mapper/BaseObjectMapper.java | 46 - .../api/mapper/JsonObjectMapper.java | 29 - .../api/mapper/WorkflowModule.java | 133 --- .../api/mapper/YamlObjectMapper.java | 30 - .../api/mapper/YamlObjectMapperFactory.java | 27 - .../serializers/AuthDefinitionSerializer.java | 68 -- .../serializers/CallbackStateSerializer.java | 50 - .../api/serializers/ContinueAsSerializer.java | 67 -- .../api/serializers/CronSerializer.java | 58 -- .../serializers/EndDefinitionSerializer.java | 72 -- .../EventDefinitionSerializer.java | 47 - .../api/serializers/EventStateSerializer.java | 49 - .../api/serializers/ExtensionSerializer.java | 60 -- .../serializers/ForEachStateSerializer.java | 49 - .../serializers/FunctionRefSerializer.java | 69 -- .../serializers/InjectStateSerializer.java | 49 - .../serializers/OperationStateSerializer.java | 51 - .../serializers/ParallelStateSerializer.java | 50 - .../api/serializers/ScheduleSerializer.java | 63 -- .../api/serializers/SleepStateSerializer.java | 49 - .../StartDefinitionSerializer.java | 58 -- .../StateExecTimeoutSerializer.java | 58 -- .../api/serializers/SubFlowRefSerializer.java | 67 -- .../serializers/SwitchStateSerializer.java | 49 - .../api/serializers/TransitionSerializer.java | 68 -- .../api/serializers/WorkflowSerializer.java | 206 ---- .../serverlessworkflow/api/utils/Utils.java | 52 - .../api/validation/ValidationError.java | 46 - .../api/validation/WorkflowSchemaLoader.java | 37 - .../serverlessworkflow/api/workflow/Auth.java | 58 -- .../api/workflow/BaseWorkflow.java | 75 -- .../api/workflow/Constants.java | 50 - .../api/workflow/DataInputSchema.java | 55 - .../api/workflow/Errors.java | 51 - .../api/workflow/Events.java | 51 - .../api/workflow/Functions.java | 51 - .../api/workflow/Retries.java | 51 - .../api/workflow/Secrets.java | 50 - .../main/resources/schema/actions/action.json | 75 -- api/src/main/resources/schema/auth/auth.json | 34 - .../resources/schema/auth/basicauthdef.json | 23 - .../resources/schema/auth/bearerauthdef.json | 17 - .../main/resources/schema/auth/oauthdef.json | 79 -- .../resources/schema/branches/branch.json | 35 - .../schema/correlation/correlationdef.json | 20 - .../main/resources/schema/cron/crondef.json | 18 - .../defaultcondition/defaultconditiondef.json | 27 - .../main/resources/schema/end/continueas.json | 28 - api/src/main/resources/schema/end/end.json | 31 - .../main/resources/schema/error/error.json | 31 - .../main/resources/schema/error/errordef.json | 23 - .../resources/schema/events/eventdef.json | 62 -- .../resources/schema/events/eventref.json | 41 - .../resources/schema/events/onevents.json | 39 - .../schema/filters/actiondatafilter.json | 24 - .../schema/filters/eventdatafilter.json | 20 - .../schema/filters/statedatafilter.json | 15 - .../schema/functions/functiondef.json | 41 - .../schema/functions/functionref.json | 32 - .../schema/functions/subflowref.json | 36 - .../resources/schema/metadata/metadata.json | 5 - .../schema/produce/produceevent.json | 23 - .../main/resources/schema/repeat/repeat.json | 37 - .../main/resources/schema/retry/retrydef.json | 43 - .../resources/schema/schedule/schedule.json | 31 - .../main/resources/schema/sleep/sleep.json | 18 - .../main/resources/schema/start/start.json | 18 - .../schema/states/callbackstate.json | 32 - .../resources/schema/states/defaultstate.json | 69 -- .../resources/schema/states/eventstate.json | 29 - .../resources/schema/states/foreachstate.json | 135 --- .../resources/schema/states/injectstate.json | 26 - .../schema/states/operationstate.json | 39 - .../schema/states/parallelstate.json | 40 - .../resources/schema/states/sleepstate.json | 25 - .../resources/schema/states/switchstate.json | 41 - .../switchconditions/datacondition.json | 40 - .../switchconditions/eventcondition.json | 32 - .../schema/timeouts/stateexectimeout.json | 19 - .../schema/timeouts/timeoutsdef.json | 29 - .../schema/timeouts/workflowexectimeout.json | 24 - .../schema/transitions/transition.json | 27 - api/src/main/resources/schema/workflow.json | 174 ---- api/src/main/resources/schema/workflow.yaml | 921 +++++++++++++++++ .../serverlessworkflow/api/FeaturesTest.java | 69 ++ .../api/test/CodegenTest.java | 32 - .../api/test/MarkupToWorkflowTest.java | 965 ------------------ .../api/test/WorkflowToMarkupTest.java | 239 ----- .../api/test/utils/WorkflowTestUtils.java | 64 -- .../resources/examples/applicantrequest.json | 60 -- .../resources/examples/applicantrequest.yml | 33 - .../test/resources/examples/booklending.json | 130 --- .../test/resources/examples/booklending.yml | 75 -- .../resources/examples/carauctionbids.json | 45 - .../resources/examples/carauctionbids.yml | 28 - .../resources/examples/checkcarvitals.json | 122 --- .../resources/examples/checkcarvitals.yml | 64 -- .../test/resources/examples/creditcheck.json | 92 -- .../test/resources/examples/creditcheck.yml | 52 - .../examples/eventbasedgreeting.json | 47 - .../resources/examples/eventbasedgreeting.yml | 29 - .../examples/eventbasedtransition.json | 72 -- .../examples/eventbasedtransition.yml | 40 - .../examples/finalizecollegeapplication.json | 74 -- .../examples/finalizecollegeapplication.yml | 40 - .../examples/foreachstatewithactions.json | 32 - .../examples/foreachstatewithactions.yml | 21 - api/src/test/resources/examples/greeting.json | 34 - api/src/test/resources/examples/greeting.yml | 20 - .../test/resources/examples/helloworld.json | 18 - .../test/resources/examples/helloworld.yml | 12 - .../resources/examples/jobmonitoring.json | 143 --- .../test/resources/examples/jobmonitoring.yml | 81 -- .../resources/examples/monitorpatient.json | 96 -- .../resources/examples/monitorpatient.yml | 56 - api/src/test/resources/examples/parallel.json | 24 - api/src/test/resources/examples/parallel.yml | 14 - .../examples/periodicinboxcheck.json | 53 - .../resources/examples/periodicinboxcheck.yml | 31 - .../resources/examples/provisionorder.json | 89 -- .../resources/examples/provisionorder.yml | 48 - .../test/resources/examples/roomreadings.json | 85 -- .../test/resources/examples/roomreadings.yml | 48 - .../resources/examples/sendcloudevent.json | 45 - .../resources/examples/sendcloudevent.yml | 27 - .../resources/examples/solvemathproblems.json | 37 - .../resources/examples/solvemathproblems.yml | 23 - .../examples/vetappointmentservice.json | 43 - .../examples/vetappointmentservice.yml | 27 - .../test/resources/features/actionssleep.json | 47 - .../test/resources/features/actionssleep.yml | 28 - .../test/resources/features/annotations.json | 6 - .../test/resources/features/annotations.yml | 8 - .../applicantrequest-with-id-and-key.json | 60 -- .../applicantrequest-with-id-and-key.yml | 34 - .../features/applicantrequest-with-key.json | 59 -- .../features/applicantrequest-with-key.yml | 33 - .../resources/features/applicantrequest.json | 59 -- .../resources/features/applicantrequest.yml | 33 - .../features/applicantrequestfunctions.json | 8 - .../features/applicantrequestfunctions.yml | 3 - .../features/applicantrequestretries.json | 9 - .../features/applicantrequestretries.yml | 4 - .../test/resources/features/authbasic.json | 15 - api/src/test/resources/features/authbasic.yml | 9 - .../test/resources/features/authbearer.json | 14 - .../test/resources/features/authbearer.yml | 8 - .../test/resources/features/authoauth.json | 15 - api/src/test/resources/features/authoauth.yml | 11 - api/src/test/resources/features/callHttp.yaml | 13 + .../test/resources/features/callOpenAPI.yaml | 15 + .../resources/features/checkcarvitals.json | 71 -- .../resources/features/checkcarvitals.yml | 41 - .../features/compensationworkflow.json | 85 -- .../features/compensationworkflow.yml | 46 - .../test/resources/features/composite.yaml | 17 + .../test/resources/features/constants.json | 38 - api/src/test/resources/features/constants.yml | 23 - .../test/resources/features/constantsRef.json | 17 - .../test/resources/features/constantsRef.yml | 14 - .../resources/features/continueasobject.json | 48 - .../resources/features/continueasobject.yml | 28 - .../resources/features/continueasstring.json | 41 - .../resources/features/continueasstring.yml | 23 - .../test/resources/features/data-flow.yaml | 21 + .../features/datainputschemaobj.json | 42 - .../resources/features/datainputschemaobj.yml | 26 - .../features/datainputschemaobjstring.json | 29 - .../features/datainputschemaobjstring.yml | 18 - .../features/datainputschemastring.json | 32 - .../features/datainputschemastring.yml | 20 - .../datainputschemawithnullschema.json | 32 - api/src/test/resources/features/emit.yaml | 13 + api/src/test/resources/features/errors.json | 39 - api/src/test/resources/features/errors.yml | 27 - .../resources/features/eventdefdataonly.json | 73 -- .../resources/features/eventdefdataonly.yml | 41 - .../resources/features/expressionlang.json | 29 - .../resources/features/expressionlang.yml | 17 - api/src/test/resources/features/flow.yaml | 14 + api/src/test/resources/features/for.yaml | 12 + .../features/functionrefjsonparams.json | 30 - .../features/functionrefjsonparams.yml | 19 - .../features/functionrefnoparams.json | 24 - .../features/functionrefnoparams.yml | 13 - .../test/resources/features/functionrefs.json | 39 - .../test/resources/features/functionrefs.yml | 22 - .../resources/features/functiontypes.json | 36 - .../test/resources/features/functiontypes.yml | 21 - api/src/test/resources/features/invoke.json | 39 - api/src/test/resources/features/invoke.yml | 24 - .../features/keepactiveexectimeout.json | 15 - .../features/keepactiveexectimeout.yml | 10 - .../test/resources/features/longstart.json | 33 - api/src/test/resources/features/longstart.yml | 19 - api/src/test/resources/features/raise.yaml | 11 + .../test/resources/features/retriesprops.json | 33 - .../test/resources/features/retriesprops.yml | 21 - api/src/test/resources/features/secrets.json | 30 - api/src/test/resources/features/secrets.yml | 21 - api/src/test/resources/features/set.yaml | 10 + .../test/resources/features/shortstart.json | 28 - .../test/resources/features/shortstart.yml | 16 - .../test/resources/features/simplecron.json | 53 - .../test/resources/features/simplecron.yml | 31 - .../resources/features/simpleschedule.json | 51 - .../resources/features/simpleschedule.yml | 29 - .../resources/features/somejsonschema.json | 13 - .../test/resources/features/subflowref.json | 25 - .../test/resources/features/subflowref.yml | 15 - api/src/test/resources/features/switch.yaml | 28 + api/src/test/resources/features/timeouts.json | 52 - api/src/test/resources/features/timeouts.yml | 32 - .../test/resources/features/transitions.json | 44 - .../test/resources/features/transitions.yml | 27 - api/src/test/resources/features/try.yaml | 21 + .../resources/features/vetappointment.json | 39 - .../resources/features/vetappointment.yml | 25 - .../features/vetappointmenteventrefs.json | 14 - .../features/vetappointmenteventrefs.yml | 7 - .../features/vetappointmentretries.json | 9 - .../features/vetappointmentretries.yml | 4 - custom-generator/pom.xml | 39 + .../generator/UnreferencedFactory.java | 59 ++ diagram-rest/.gitignore | 31 - diagram-rest/pom.xml | 58 -- .../diagramrest/Application.java | 26 - .../diagramrest/DiagramRequest.java | 43 - .../diagramrest/DiagramRequestHelper.java | 44 - .../diagramrest/RouterRest.java | 34 - .../diagramrest/RouterRestInterface.java | 55 - .../src/main/resources/application.yml | 12 - .../templates/plantuml/custom-template.txt | 46 - .../diagramrest/DiagramGenerationTest.java | 75 -- diagram/.gitignore | 31 - diagram/pom.xml | 152 --- .../diagram/WorkflowDiagramImpl.java | 78 -- .../diagram/config/ThymeleafConfig.java | 41 - .../diagram/model/ModelConnection.java | 71 -- .../diagram/model/ModelState.java | 54 - .../diagram/model/ModelStateDef.java | 44 - .../diagram/model/WorkflowDiagramModel.java | 477 --------- .../diagram/utils/WorkflowDiagramUtils.java | 61 -- .../diagram/utils/WorkflowToPlantuml.java | 33 - ...essworkflow.api.interfaces.WorkflowDiagram | 1 - .../templates/plantuml/workflow-template.txt | 46 - .../CustomTemplateWorkflowDiagramTest.java | 52 - .../diagram/test/WorkflowDiagramTest.java | 90 -- .../diagram/test/utils/DiagramTestUtils.java | 64 -- .../resources/examples/applicantrequest.json | 59 -- .../resources/examples/applicantrequest.yml | 33 - .../test/resources/examples/booklending.json | 130 --- .../test/resources/examples/booklending.yml | 75 -- .../resources/examples/carauctionbids.json | 45 - .../resources/examples/carauctionbids.yml | 28 - .../resources/examples/checkcarvitals.json | 122 --- .../resources/examples/checkcarvitals.yml | 64 -- .../test/resources/examples/creditcheck.json | 92 -- .../test/resources/examples/creditcheck.yml | 52 - .../examples/eventbasedgreeting.json | 47 - .../resources/examples/eventbasedgreeting.yml | 29 - .../examples/eventbasedtransition.json | 72 -- .../examples/eventbasedtransition.yml | 40 - .../examples/finalizecollegeapplication.json | 74 -- .../examples/finalizecollegeapplication.yml | 40 - .../examples/foreachstatewithactions.json | 33 - .../examples/foreachstatewithactions.yml | 21 - .../src/test/resources/examples/greeting.json | 34 - .../src/test/resources/examples/greeting.yml | 20 - .../test/resources/examples/helloworld.json | 18 - .../test/resources/examples/helloworld.yml | 12 - .../resources/examples/jobmonitoring.json | 143 --- .../test/resources/examples/jobmonitoring.yml | 81 -- .../resources/examples/monitorpatient.json | 96 -- .../resources/examples/monitorpatient.yml | 56 - .../src/test/resources/examples/parallel.json | 24 - .../src/test/resources/examples/parallel.yml | 14 - .../examples/periodicinboxcheck.json | 53 - .../resources/examples/periodicinboxcheck.yml | 31 - .../resources/examples/provisionorder.json | 89 -- .../resources/examples/provisionorder.yml | 48 - .../test/resources/examples/roomreadings.json | 85 -- .../test/resources/examples/roomreadings.yml | 48 - .../resources/examples/sendcloudevent.json | 45 - .../resources/examples/sendcloudevent.yml | 27 - .../resources/examples/singleeventstate.json | 47 - .../resources/examples/singleeventstate.yml | 33 - .../resources/examples/singleswitchstate.json | 48 - .../resources/examples/singleswitchstate.yml | 31 - .../singleswitchstateeventconditions.json | 48 - .../singleswitchstateeventconditions.yml | 31 - .../resources/examples/solvemathproblems.json | 37 - .../resources/examples/solvemathproblems.yml | 23 - .../examples/vetappointmentservice.json | 43 - .../examples/vetappointmentservice.yml | 27 - .../templates/plantuml/custom-template.txt | 46 - img/jobmonitoring.png | Bin 120051 -> 0 bytes img/provisionorders.png | Bin 51023 -> 0 bytes pom.xml | 11 +- spi/.gitignore | 31 - spi/pom.xml | 124 --- .../spi/WorkflowDiagramProvider.java | 51 - .../spi/WorkflowPropertySourceProvider.java | 51 - .../spi/WorkflowValidatorProvider.java | 51 - .../spi/test/ServiceProvidersTest.java | 42 - .../providers/TestWorkflowPropertySource.java | 44 - .../test/providers/TestWorkflowValidator.java | 54 - ...flow.api.interfaces.WorkflowPropertySource | 1 - ...sworkflow.api.interfaces.WorkflowValidator | 1 - utils/pom.xml | 124 --- .../utils/WorkflowUtils.java | 665 ------------ .../util/DefinedEventsTest.java | 79 -- .../serverlessworkflow/util/EventsTest.java | 76 -- .../util/FunctionDefinitionsTest.java | 78 -- .../util/FunctionsWithTypeTest.java | 42 - .../serverlessworkflow/util/GetNumTests.java | 61 -- .../util/GetStatesTest.java | 65 -- .../util/JsonManipulationTest.java | 97 -- .../util/StartStateTest.java | 63 -- .../util/testutil/TestUtils.java | 54 - .../resources/events/workflowwithevents.yml | 56 - .../events/workflowwithproducedevents.yml | 59 -- .../funcdefinitiontest/functiondefinition.yml | 58 -- .../functiontypes/workflowfunctiontypes.yml | 22 - .../getStates/workflowwithstates.yml | 55 - .../resources/start/workflowwithnostate.yml | 24 - .../start/workflowwithstartnotspecified.yml | 39 - .../start/workflowwithstartstate.yml | 40 - validation/.gitignore | 31 - validation/pom.xml | 146 --- .../validation/WorkflowValidatorImpl.java | 432 -------- ...sworkflow.api.interfaces.WorkflowValidator | 1 - .../test/WorkflowValidationTest.java | 524 ---------- 373 files changed, 1496 insertions(+), 19761 deletions(-) create mode 100644 api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java rename api/src/main/java/io/serverlessworkflow/api/{mapper/JsonObjectMapperFactory.java => WorkflowFormat.java} (54%) create mode 100644 api/src/main/java/io/serverlessworkflow/api/WorkflowReader.java create mode 100644 api/src/main/java/io/serverlessworkflow/api/WorkflowWriter.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDefinitionDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/ContinueAsDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/CronDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/DataInputSchemaDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/DefaultStateTypeDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/EndDefinitionDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/EventDefinitionKindDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/ExtensionDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionDefinitionTypeDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionRefDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/OnEventsActionModeDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/OperationStateActionModeDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/ParallelStateCompletionTypeDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/ScheduleDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/StartDefinitionDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/StateDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/StateExecTimeoutDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/StringValueDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/SubFlowRefDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/deserializers/TransitionDeserializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/interfaces/Extension.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/interfaces/State.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/interfaces/SwitchCondition.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowDiagram.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowPropertySource.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowValidator.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/mapper/BaseObjectMapper.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapper.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/mapper/WorkflowModule.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapper.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/AuthDefinitionSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/CallbackStateSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/ContinueAsSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/CronSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/EndDefinitionSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/EventDefinitionSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/EventStateSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/ExtensionSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/ForEachStateSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/FunctionRefSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/InjectStateSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/OperationStateSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/ParallelStateSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/ScheduleSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/SleepStateSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/StartDefinitionSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/StateExecTimeoutSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/SubFlowRefSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/SwitchStateSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/TransitionSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/serializers/WorkflowSerializer.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/utils/Utils.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/validation/ValidationError.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/workflow/Auth.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/workflow/BaseWorkflow.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/workflow/Constants.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/workflow/DataInputSchema.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/workflow/Errors.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/workflow/Events.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/workflow/Functions.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/workflow/Retries.java delete mode 100644 api/src/main/java/io/serverlessworkflow/api/workflow/Secrets.java delete mode 100644 api/src/main/resources/schema/actions/action.json delete mode 100644 api/src/main/resources/schema/auth/auth.json delete mode 100644 api/src/main/resources/schema/auth/basicauthdef.json delete mode 100644 api/src/main/resources/schema/auth/bearerauthdef.json delete mode 100644 api/src/main/resources/schema/auth/oauthdef.json delete mode 100644 api/src/main/resources/schema/branches/branch.json delete mode 100644 api/src/main/resources/schema/correlation/correlationdef.json delete mode 100644 api/src/main/resources/schema/cron/crondef.json delete mode 100644 api/src/main/resources/schema/defaultcondition/defaultconditiondef.json delete mode 100644 api/src/main/resources/schema/end/continueas.json delete mode 100644 api/src/main/resources/schema/end/end.json delete mode 100644 api/src/main/resources/schema/error/error.json delete mode 100644 api/src/main/resources/schema/error/errordef.json delete mode 100644 api/src/main/resources/schema/events/eventdef.json delete mode 100644 api/src/main/resources/schema/events/eventref.json delete mode 100644 api/src/main/resources/schema/events/onevents.json delete mode 100644 api/src/main/resources/schema/filters/actiondatafilter.json delete mode 100644 api/src/main/resources/schema/filters/eventdatafilter.json delete mode 100644 api/src/main/resources/schema/filters/statedatafilter.json delete mode 100644 api/src/main/resources/schema/functions/functiondef.json delete mode 100644 api/src/main/resources/schema/functions/functionref.json delete mode 100644 api/src/main/resources/schema/functions/subflowref.json delete mode 100644 api/src/main/resources/schema/metadata/metadata.json delete mode 100644 api/src/main/resources/schema/produce/produceevent.json delete mode 100644 api/src/main/resources/schema/repeat/repeat.json delete mode 100644 api/src/main/resources/schema/retry/retrydef.json delete mode 100644 api/src/main/resources/schema/schedule/schedule.json delete mode 100644 api/src/main/resources/schema/sleep/sleep.json delete mode 100644 api/src/main/resources/schema/start/start.json delete mode 100644 api/src/main/resources/schema/states/callbackstate.json delete mode 100644 api/src/main/resources/schema/states/defaultstate.json delete mode 100644 api/src/main/resources/schema/states/eventstate.json delete mode 100644 api/src/main/resources/schema/states/foreachstate.json delete mode 100644 api/src/main/resources/schema/states/injectstate.json delete mode 100644 api/src/main/resources/schema/states/operationstate.json delete mode 100644 api/src/main/resources/schema/states/parallelstate.json delete mode 100644 api/src/main/resources/schema/states/sleepstate.json delete mode 100644 api/src/main/resources/schema/states/switchstate.json delete mode 100644 api/src/main/resources/schema/switchconditions/datacondition.json delete mode 100644 api/src/main/resources/schema/switchconditions/eventcondition.json delete mode 100644 api/src/main/resources/schema/timeouts/stateexectimeout.json delete mode 100644 api/src/main/resources/schema/timeouts/timeoutsdef.json delete mode 100644 api/src/main/resources/schema/timeouts/workflowexectimeout.json delete mode 100644 api/src/main/resources/schema/transitions/transition.json delete mode 100644 api/src/main/resources/schema/workflow.json create mode 100644 api/src/main/resources/schema/workflow.yaml create mode 100644 api/src/test/java/io/serverlessworkflow/api/FeaturesTest.java delete mode 100644 api/src/test/java/io/serverlessworkflow/api/test/CodegenTest.java delete mode 100644 api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java delete mode 100644 api/src/test/java/io/serverlessworkflow/api/test/WorkflowToMarkupTest.java delete mode 100644 api/src/test/java/io/serverlessworkflow/api/test/utils/WorkflowTestUtils.java delete mode 100644 api/src/test/resources/examples/applicantrequest.json delete mode 100644 api/src/test/resources/examples/applicantrequest.yml delete mode 100644 api/src/test/resources/examples/booklending.json delete mode 100644 api/src/test/resources/examples/booklending.yml delete mode 100644 api/src/test/resources/examples/carauctionbids.json delete mode 100644 api/src/test/resources/examples/carauctionbids.yml delete mode 100644 api/src/test/resources/examples/checkcarvitals.json delete mode 100644 api/src/test/resources/examples/checkcarvitals.yml delete mode 100644 api/src/test/resources/examples/creditcheck.json delete mode 100644 api/src/test/resources/examples/creditcheck.yml delete mode 100644 api/src/test/resources/examples/eventbasedgreeting.json delete mode 100644 api/src/test/resources/examples/eventbasedgreeting.yml delete mode 100644 api/src/test/resources/examples/eventbasedtransition.json delete mode 100644 api/src/test/resources/examples/eventbasedtransition.yml delete mode 100644 api/src/test/resources/examples/finalizecollegeapplication.json delete mode 100644 api/src/test/resources/examples/finalizecollegeapplication.yml delete mode 100644 api/src/test/resources/examples/foreachstatewithactions.json delete mode 100644 api/src/test/resources/examples/foreachstatewithactions.yml delete mode 100644 api/src/test/resources/examples/greeting.json delete mode 100644 api/src/test/resources/examples/greeting.yml delete mode 100644 api/src/test/resources/examples/helloworld.json delete mode 100644 api/src/test/resources/examples/helloworld.yml delete mode 100644 api/src/test/resources/examples/jobmonitoring.json delete mode 100644 api/src/test/resources/examples/jobmonitoring.yml delete mode 100644 api/src/test/resources/examples/monitorpatient.json delete mode 100644 api/src/test/resources/examples/monitorpatient.yml delete mode 100644 api/src/test/resources/examples/parallel.json delete mode 100644 api/src/test/resources/examples/parallel.yml delete mode 100644 api/src/test/resources/examples/periodicinboxcheck.json delete mode 100644 api/src/test/resources/examples/periodicinboxcheck.yml delete mode 100644 api/src/test/resources/examples/provisionorder.json delete mode 100644 api/src/test/resources/examples/provisionorder.yml delete mode 100644 api/src/test/resources/examples/roomreadings.json delete mode 100644 api/src/test/resources/examples/roomreadings.yml delete mode 100644 api/src/test/resources/examples/sendcloudevent.json delete mode 100644 api/src/test/resources/examples/sendcloudevent.yml delete mode 100644 api/src/test/resources/examples/solvemathproblems.json delete mode 100644 api/src/test/resources/examples/solvemathproblems.yml delete mode 100644 api/src/test/resources/examples/vetappointmentservice.json delete mode 100644 api/src/test/resources/examples/vetappointmentservice.yml delete mode 100644 api/src/test/resources/features/actionssleep.json delete mode 100644 api/src/test/resources/features/actionssleep.yml delete mode 100644 api/src/test/resources/features/annotations.json delete mode 100644 api/src/test/resources/features/annotations.yml delete mode 100644 api/src/test/resources/features/applicantrequest-with-id-and-key.json delete mode 100644 api/src/test/resources/features/applicantrequest-with-id-and-key.yml delete mode 100644 api/src/test/resources/features/applicantrequest-with-key.json delete mode 100644 api/src/test/resources/features/applicantrequest-with-key.yml delete mode 100644 api/src/test/resources/features/applicantrequest.json delete mode 100644 api/src/test/resources/features/applicantrequest.yml delete mode 100644 api/src/test/resources/features/applicantrequestfunctions.json delete mode 100644 api/src/test/resources/features/applicantrequestfunctions.yml delete mode 100644 api/src/test/resources/features/applicantrequestretries.json delete mode 100644 api/src/test/resources/features/applicantrequestretries.yml delete mode 100644 api/src/test/resources/features/authbasic.json delete mode 100644 api/src/test/resources/features/authbasic.yml delete mode 100644 api/src/test/resources/features/authbearer.json delete mode 100644 api/src/test/resources/features/authbearer.yml delete mode 100644 api/src/test/resources/features/authoauth.json delete mode 100644 api/src/test/resources/features/authoauth.yml create mode 100644 api/src/test/resources/features/callHttp.yaml create mode 100644 api/src/test/resources/features/callOpenAPI.yaml delete mode 100644 api/src/test/resources/features/checkcarvitals.json delete mode 100644 api/src/test/resources/features/checkcarvitals.yml delete mode 100644 api/src/test/resources/features/compensationworkflow.json delete mode 100644 api/src/test/resources/features/compensationworkflow.yml create mode 100644 api/src/test/resources/features/composite.yaml delete mode 100644 api/src/test/resources/features/constants.json delete mode 100644 api/src/test/resources/features/constants.yml delete mode 100644 api/src/test/resources/features/constantsRef.json delete mode 100644 api/src/test/resources/features/constantsRef.yml delete mode 100644 api/src/test/resources/features/continueasobject.json delete mode 100644 api/src/test/resources/features/continueasobject.yml delete mode 100644 api/src/test/resources/features/continueasstring.json delete mode 100644 api/src/test/resources/features/continueasstring.yml create mode 100644 api/src/test/resources/features/data-flow.yaml delete mode 100644 api/src/test/resources/features/datainputschemaobj.json delete mode 100644 api/src/test/resources/features/datainputschemaobj.yml delete mode 100644 api/src/test/resources/features/datainputschemaobjstring.json delete mode 100644 api/src/test/resources/features/datainputschemaobjstring.yml delete mode 100644 api/src/test/resources/features/datainputschemastring.json delete mode 100644 api/src/test/resources/features/datainputschemastring.yml delete mode 100644 api/src/test/resources/features/datainputschemawithnullschema.json create mode 100644 api/src/test/resources/features/emit.yaml delete mode 100644 api/src/test/resources/features/errors.json delete mode 100644 api/src/test/resources/features/errors.yml delete mode 100644 api/src/test/resources/features/eventdefdataonly.json delete mode 100644 api/src/test/resources/features/eventdefdataonly.yml delete mode 100644 api/src/test/resources/features/expressionlang.json delete mode 100644 api/src/test/resources/features/expressionlang.yml create mode 100644 api/src/test/resources/features/flow.yaml create mode 100644 api/src/test/resources/features/for.yaml delete mode 100644 api/src/test/resources/features/functionrefjsonparams.json delete mode 100644 api/src/test/resources/features/functionrefjsonparams.yml delete mode 100644 api/src/test/resources/features/functionrefnoparams.json delete mode 100644 api/src/test/resources/features/functionrefnoparams.yml delete mode 100644 api/src/test/resources/features/functionrefs.json delete mode 100644 api/src/test/resources/features/functionrefs.yml delete mode 100644 api/src/test/resources/features/functiontypes.json delete mode 100644 api/src/test/resources/features/functiontypes.yml delete mode 100644 api/src/test/resources/features/invoke.json delete mode 100644 api/src/test/resources/features/invoke.yml delete mode 100644 api/src/test/resources/features/keepactiveexectimeout.json delete mode 100644 api/src/test/resources/features/keepactiveexectimeout.yml delete mode 100644 api/src/test/resources/features/longstart.json delete mode 100644 api/src/test/resources/features/longstart.yml create mode 100644 api/src/test/resources/features/raise.yaml delete mode 100644 api/src/test/resources/features/retriesprops.json delete mode 100644 api/src/test/resources/features/retriesprops.yml delete mode 100644 api/src/test/resources/features/secrets.json delete mode 100644 api/src/test/resources/features/secrets.yml create mode 100644 api/src/test/resources/features/set.yaml delete mode 100644 api/src/test/resources/features/shortstart.json delete mode 100644 api/src/test/resources/features/shortstart.yml delete mode 100644 api/src/test/resources/features/simplecron.json delete mode 100644 api/src/test/resources/features/simplecron.yml delete mode 100644 api/src/test/resources/features/simpleschedule.json delete mode 100644 api/src/test/resources/features/simpleschedule.yml delete mode 100644 api/src/test/resources/features/somejsonschema.json delete mode 100644 api/src/test/resources/features/subflowref.json delete mode 100644 api/src/test/resources/features/subflowref.yml create mode 100644 api/src/test/resources/features/switch.yaml delete mode 100644 api/src/test/resources/features/timeouts.json delete mode 100644 api/src/test/resources/features/timeouts.yml delete mode 100644 api/src/test/resources/features/transitions.json delete mode 100644 api/src/test/resources/features/transitions.yml create mode 100644 api/src/test/resources/features/try.yaml delete mode 100644 api/src/test/resources/features/vetappointment.json delete mode 100644 api/src/test/resources/features/vetappointment.yml delete mode 100644 api/src/test/resources/features/vetappointmenteventrefs.json delete mode 100644 api/src/test/resources/features/vetappointmenteventrefs.yml delete mode 100644 api/src/test/resources/features/vetappointmentretries.json delete mode 100644 api/src/test/resources/features/vetappointmentretries.yml create mode 100644 custom-generator/pom.xml create mode 100644 custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java delete mode 100644 diagram-rest/.gitignore delete mode 100644 diagram-rest/pom.xml delete mode 100644 diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/Application.java delete mode 100644 diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/DiagramRequest.java delete mode 100644 diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/DiagramRequestHelper.java delete mode 100644 diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/RouterRest.java delete mode 100644 diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/RouterRestInterface.java delete mode 100644 diagram-rest/src/main/resources/application.yml delete mode 100644 diagram-rest/src/main/resources/templates/plantuml/custom-template.txt delete mode 100644 diagram-rest/src/test/java/io/serverlessworkflow/diagramrest/DiagramGenerationTest.java delete mode 100644 diagram/.gitignore delete mode 100644 diagram/pom.xml delete mode 100644 diagram/src/main/java/io/serverlessworkflow/diagram/WorkflowDiagramImpl.java delete mode 100644 diagram/src/main/java/io/serverlessworkflow/diagram/config/ThymeleafConfig.java delete mode 100644 diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelConnection.java delete mode 100644 diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelState.java delete mode 100644 diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelStateDef.java delete mode 100644 diagram/src/main/java/io/serverlessworkflow/diagram/model/WorkflowDiagramModel.java delete mode 100644 diagram/src/main/java/io/serverlessworkflow/diagram/utils/WorkflowDiagramUtils.java delete mode 100644 diagram/src/main/java/io/serverlessworkflow/diagram/utils/WorkflowToPlantuml.java delete mode 100644 diagram/src/main/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowDiagram delete mode 100644 diagram/src/main/resources/templates/plantuml/workflow-template.txt delete mode 100644 diagram/src/test/java/io/serverlessworkflow/diagram/test/CustomTemplateWorkflowDiagramTest.java delete mode 100644 diagram/src/test/java/io/serverlessworkflow/diagram/test/WorkflowDiagramTest.java delete mode 100644 diagram/src/test/java/io/serverlessworkflow/diagram/test/utils/DiagramTestUtils.java delete mode 100644 diagram/src/test/resources/examples/applicantrequest.json delete mode 100644 diagram/src/test/resources/examples/applicantrequest.yml delete mode 100644 diagram/src/test/resources/examples/booklending.json delete mode 100644 diagram/src/test/resources/examples/booklending.yml delete mode 100644 diagram/src/test/resources/examples/carauctionbids.json delete mode 100644 diagram/src/test/resources/examples/carauctionbids.yml delete mode 100644 diagram/src/test/resources/examples/checkcarvitals.json delete mode 100644 diagram/src/test/resources/examples/checkcarvitals.yml delete mode 100644 diagram/src/test/resources/examples/creditcheck.json delete mode 100644 diagram/src/test/resources/examples/creditcheck.yml delete mode 100644 diagram/src/test/resources/examples/eventbasedgreeting.json delete mode 100644 diagram/src/test/resources/examples/eventbasedgreeting.yml delete mode 100644 diagram/src/test/resources/examples/eventbasedtransition.json delete mode 100644 diagram/src/test/resources/examples/eventbasedtransition.yml delete mode 100644 diagram/src/test/resources/examples/finalizecollegeapplication.json delete mode 100644 diagram/src/test/resources/examples/finalizecollegeapplication.yml delete mode 100644 diagram/src/test/resources/examples/foreachstatewithactions.json delete mode 100644 diagram/src/test/resources/examples/foreachstatewithactions.yml delete mode 100644 diagram/src/test/resources/examples/greeting.json delete mode 100644 diagram/src/test/resources/examples/greeting.yml delete mode 100644 diagram/src/test/resources/examples/helloworld.json delete mode 100644 diagram/src/test/resources/examples/helloworld.yml delete mode 100644 diagram/src/test/resources/examples/jobmonitoring.json delete mode 100644 diagram/src/test/resources/examples/jobmonitoring.yml delete mode 100644 diagram/src/test/resources/examples/monitorpatient.json delete mode 100644 diagram/src/test/resources/examples/monitorpatient.yml delete mode 100644 diagram/src/test/resources/examples/parallel.json delete mode 100644 diagram/src/test/resources/examples/parallel.yml delete mode 100644 diagram/src/test/resources/examples/periodicinboxcheck.json delete mode 100644 diagram/src/test/resources/examples/periodicinboxcheck.yml delete mode 100644 diagram/src/test/resources/examples/provisionorder.json delete mode 100644 diagram/src/test/resources/examples/provisionorder.yml delete mode 100644 diagram/src/test/resources/examples/roomreadings.json delete mode 100644 diagram/src/test/resources/examples/roomreadings.yml delete mode 100644 diagram/src/test/resources/examples/sendcloudevent.json delete mode 100644 diagram/src/test/resources/examples/sendcloudevent.yml delete mode 100644 diagram/src/test/resources/examples/singleeventstate.json delete mode 100644 diagram/src/test/resources/examples/singleeventstate.yml delete mode 100644 diagram/src/test/resources/examples/singleswitchstate.json delete mode 100644 diagram/src/test/resources/examples/singleswitchstate.yml delete mode 100644 diagram/src/test/resources/examples/singleswitchstateeventconditions.json delete mode 100644 diagram/src/test/resources/examples/singleswitchstateeventconditions.yml delete mode 100644 diagram/src/test/resources/examples/solvemathproblems.json delete mode 100644 diagram/src/test/resources/examples/solvemathproblems.yml delete mode 100644 diagram/src/test/resources/examples/vetappointmentservice.json delete mode 100644 diagram/src/test/resources/examples/vetappointmentservice.yml delete mode 100644 diagram/src/test/resources/templates/plantuml/custom-template.txt delete mode 100644 img/jobmonitoring.png delete mode 100644 img/provisionorders.png delete mode 100644 spi/.gitignore delete mode 100644 spi/pom.xml delete mode 100644 spi/src/main/java/io/serverlessworkflow/spi/WorkflowDiagramProvider.java delete mode 100644 spi/src/main/java/io/serverlessworkflow/spi/WorkflowPropertySourceProvider.java delete mode 100644 spi/src/main/java/io/serverlessworkflow/spi/WorkflowValidatorProvider.java delete mode 100644 spi/src/test/java/io/serverlessworkflow/spi/test/ServiceProvidersTest.java delete mode 100644 spi/src/test/java/io/serverlessworkflow/spi/test/providers/TestWorkflowPropertySource.java delete mode 100644 spi/src/test/java/io/serverlessworkflow/spi/test/providers/TestWorkflowValidator.java delete mode 100644 spi/src/test/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowPropertySource delete mode 100644 spi/src/test/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowValidator delete mode 100644 utils/pom.xml delete mode 100644 utils/src/main/java/io/serverlessworkflow/utils/WorkflowUtils.java delete mode 100644 utils/src/test/java/io/serverlessworkflow/util/DefinedEventsTest.java delete mode 100644 utils/src/test/java/io/serverlessworkflow/util/EventsTest.java delete mode 100644 utils/src/test/java/io/serverlessworkflow/util/FunctionDefinitionsTest.java delete mode 100644 utils/src/test/java/io/serverlessworkflow/util/FunctionsWithTypeTest.java delete mode 100644 utils/src/test/java/io/serverlessworkflow/util/GetNumTests.java delete mode 100644 utils/src/test/java/io/serverlessworkflow/util/GetStatesTest.java delete mode 100644 utils/src/test/java/io/serverlessworkflow/util/JsonManipulationTest.java delete mode 100644 utils/src/test/java/io/serverlessworkflow/util/StartStateTest.java delete mode 100644 utils/src/test/java/io/serverlessworkflow/util/testutil/TestUtils.java delete mode 100644 utils/src/test/resources/events/workflowwithevents.yml delete mode 100644 utils/src/test/resources/events/workflowwithproducedevents.yml delete mode 100644 utils/src/test/resources/funcdefinitiontest/functiondefinition.yml delete mode 100644 utils/src/test/resources/functiontypes/workflowfunctiontypes.yml delete mode 100644 utils/src/test/resources/getStates/workflowwithstates.yml delete mode 100644 utils/src/test/resources/start/workflowwithnostate.yml delete mode 100644 utils/src/test/resources/start/workflowwithstartnotspecified.yml delete mode 100644 utils/src/test/resources/start/workflowwithstartstate.yml delete mode 100644 validation/.gitignore delete mode 100644 validation/pom.xml delete mode 100644 validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java delete mode 100644 validation/src/main/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowValidator delete mode 100644 validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java diff --git a/README.md b/README.md index 5ac8f45f..7e908267 100644 --- a/README.md +++ b/README.md @@ -3,29 +3,28 @@ # Serverless Workflow Specification - Java SDK -Provides the Java API/SPI and Model Validation for the [Serverless Workflow Specification](https://github.com/serverlessworkflow/specification) +Provides the Java API for the [Serverless Workflow Specification](https://github.com/serverlessworkflow/specification) With the SDK you can: -* Parse workflow JSON and YAML definitions -* Programmatically build workflow definitions -* Validate workflow definitions (both schema and workflow integrity validation) -* Generate workflow diagram (SVG) -* Set of utilities to help runtimes interpret the Serverless Workflow object model +* Read workflow JSON and YAML definitions +* Write workflow in JSON and YAML format. -Serverless Workflow Java SDK is **not** a workflow runtime implementation but can be used by Java runtime implementations -to parse and validate workflow definitions as well as generate the workflow diagram (SVG). +Serverless Workflow Java SDK is **not** a workflow runtime implementation but can be used by Java runtime implementations to parse workflow definitions. ### Status | Latest Releases | Conformance to spec version | | :---: | :---: | +| [7.0.0.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/7.0.0.Final) | [v0.10](https://github.com/serverlessworkflow/specification/tree/0.10.x) | | [5.0.0.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/5.0.0.Final) | [v0.8](https://github.com/serverlessworkflow/specification/tree/0.8.x) | | [4.0.5.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/4.0.5.Final) | [v0.8](https://github.com/serverlessworkflow/specification/tree/0.8.x) | | [3.0.0.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/3.0.0.Final) | [v0.7](https://github.com/serverlessworkflow/specification/tree/0.7.x) | | [2.0.0.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/2.0.0.Final) | [v0.6](https://github.com/serverlessworkflow/specification/tree/0.6.x) | | [1.0.3.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/1.0.3.Final) | [v0.5](https://github.com/serverlessworkflow/specification/tree/0.5.x) | +Note that 6.0.0.Final, which will be the one for specification version 0.9, is skipped intentionally in case someone want to work on it. + ### JDK Version | SDK Version | JDK Version | @@ -35,10 +34,6 @@ to parse and validate workflow definitions as well as generate the workflow diag ### Getting Started -#### Using the latest release - -See instructions how to define dependencies for the latest SDK release -for both Maven and Gradle [here](https://github.com/serverlessworkflow/sdk-java/blob/4.0.x/README.md). #### Building SNAPSHOT locally @@ -54,71 +49,22 @@ Your changes should be automatically formatted during the build. #### Maven projects: -a) Add the following repository to your pom.xml `repositories` section: - -```xml - - oss.sonatype.org-snapshot - http://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - -``` - -b) Add the following dependencies to your pom.xml `dependencies` section: +Add the following dependencies to your pom.xml `dependencies` section: ```xml io.serverlessworkflow serverlessworkflow-api - 5.0.0-SNAPSHOT - - - - io.serverlessworkflow - serverlessworkflow-spi - 5.0.0-SNAPSHOT - - - - io.serverlessworkflow - serverlessworkflow-validation - 5.0.0-SNAPSHOT - - - - io.serverlessworkflow - serverlessworkflow-diagram - 5.0.0-SNAPSHOT - - - - io.serverlessworkflow - serverlessworkflow-util - 5.0.0-SNAPSHOT + 7.0.0-SNAPSHOT ``` #### Gradle projects: -a) Add the following repositories to your build.gradle `repositories` section: - -```text -maven { url "https://oss.sonatype.org/content/repositories/snapshots" } -``` - -b) Add the following dependencies to your build.gradle `dependencies` section: + Add the following dependencies to your build.gradle `dependencies` section: ```text -implementation("io.serverlessworkflow:serverlessworkflow-api:5.0.0-SNAPSHOT") -implementation("io.serverlessworkflow:serverlessworkflow-spi:5.0.0-SNAPSHOT") -implementation("io.serverlessworkflow:serverlessworkflow-validation:5.0.0-SNAPSHOT") -implementation("io.serverlessworkflow:serverlessworkflow-diagram:5.0.0-SNAPSHOT") -implementation("io.serverlessworkflow:serverlessworkflow-util:5.0.0-SNAPSHOT") +implementation("io.serverlessworkflow:serverlessworkflow-api:7.0.0-SNAPSHOT") ``` ### How to Use @@ -127,256 +73,44 @@ implementation("io.serverlessworkflow:serverlessworkflow-util:5.0.0-SNAPSHOT") You can create a Workflow instance from JSON/YAML source: -Let's say you have a simple YAML based workflow definition: +Let's say you have a simple YAML based workflow definition in a file name `simple.yaml` located in your working dir: ```yaml -id: greeting -version: '1.0' -name: Greeting Workflow -start: Greet -description: Greet Someone -functions: - - name: greetingFunction - operation: file://myapis/greetingapis.json#greeting -states: -- name: Greet - type: operation - actions: - - functionRef: - refName: greetingFunction - arguments: - name: "${ .greet.name }" - actionDataFilter: - results: "${ .payload.greeting }" - stateDataFilter: - output: "${ .greeting }" - end: true -``` - -To parse it and create a Workflow instance you can do: - -``` java -Workflow workflow = Workflow.fromSource(source); -``` - -where 'source' is the above mentioned YAML definition. - -The fromSource static method can take in definitions in both JSON and YAML formats. - -Once you have the Workflow instance you can use its API to inspect it, for example: - -``` java -assertNotNull(workflow); -assertEquals("greeting", workflow.getId()); -assertEquals("Greeting Workflow", workflow.getName()); - -assertNotNull(workflow.getFunctions()); -assertEquals(1, workflow.getFunctions().size()); -assertEquals("greetingFunction", workflow.getFunctions().get(0).getName()); - -assertNotNull(workflow.getStates()); -assertEquals(1, workflow.getStates().size()); -assertTrue(workflow.getStates().get(0) instanceof OperationState); - -OperationState operationState = (OperationState) workflow.getStates().get(0); -assertEquals("Greet", operationState.getName()); -assertEquals(DefaultState.Type.OPERATION, operationState.getType()); -... -``` - -#### Using builder API - -You can also programmatically create Workflow instances, for example: - -``` java -Workflow workflow = new Workflow() - .withId("test-workflow") - .withName("test-workflow-name") - .withVersion("1.0") - .withStart(new Start().withStateName("MyDelayState")) - .withFunctions(new Functions(Arrays.asList( - new FunctionDefinition().withName("testFunction") - .withOperation("testSwaggerDef#testOperationId"))) - ) - .withStates(Arrays.asList( - new DelayState().withName("MyDelayState").withType(DELAY) - .withTimeDelay("PT1M") - .withEnd( - new End().withTerminate(true) - ) - ) - ); -``` - -This will create a test workflow that defines an event, a function and a single Delay State. - -You can use the workflow instance to get its JSON/YAML definition as well: - -``` java -assertNotNull(Workflow.toJson(testWorkflow)); -assertNotNull(Workflow.toYaml(testWorkflow)); -``` +document: + dsl: 1.0.0-alpha1 + namespace: default + name: implicit-sequence +do: + setRed: + set: + colors: '${ .colors + [ "red" ] }' + setGreen: + set: + colors: '${ .colors + [ "green" ] }' + setBlue: + set: + colors: '${ .colors + [ "blue" ] }' -#### Using Workflow Validation - -Validation allows you to perform Json Schema validation against the JSON/YAML workflow definitions. -Once you have a `Workflow` instance, you can also run integrity checks. - -You can validate a Workflow JSON/YAML definition to get validation errors: - -``` java -WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); -List validationErrors = workflowValidator.setSource("WORKFLOW_MODEL_JSON/YAML").validate(); -``` - -Where `WORKFLOW_MODEL_JSON/YAML` is the actual workflow model JSON or YAML definition. - -Or you can just check if it is valid (without getting specific errors): - -``` java -WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); -boolean isValidWorkflow = workflowValidator.setSource("WORKFLOW_MODEL_JSON/YAML").isValid(); -``` - -If you build your Workflow programmatically, you can validate it as well: - -``` java -Workflow workflow = new Workflow() - .withId("test-workflow") - .withVersion("1.0") - .withStart(new Start().withStateName("MyDelayState")) - .withStates(Arrays.asList( - new DelayState().withName("MyDelayState").withType(DefaultState.Type.DELAY) - .withTimeDelay("PT1M") - .withEnd( - new End().withTerminate(true) - ) - )); -); - -WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); -List validationErrors = workflowValidator.setWorkflow(workflow).validate(); ``` -#### Building Workflow Diagram - -Given a valid workflow definition (JSON/YAML) or a Workflow object you can build the workflow diagram SVG. -The generated diagram SVG uses [PlantUML](https://plantuml.com/) state diagram visualization and can be embedded inside your -tooling or web pages, or any SVG viewer. - -You can build the workflow diagram SVG with the following code: +To parse it and create a Workflow instance you can do: ``` java -Workflow workflow = Workflow.fromSource(source); - -WorkflowDiagram workflowDiagram = new WorkflowDiagramImpl(); -workflowDiagram.setWorkflow(workflow); -String diagramSVG = workflowDiagram.getSvgDiagram(); +try (InputStream in = new FileInputStream("simple.yaml")) { + Workflow workflow = WorkflowReader.readWorkflow (in, WorkflowFormat.YAML); + // Once you have the Workflow instance you can use its API to inspect it +} ``` -`diagramSVG` includes the diagram SVG source which you can then decide to save to a file, -print, or process further. - -In case default visualization of the workflow is not sufficient you can provide custom workflow template to be -used while generating the SVG file. Easiest is to start off from the default template and customize it to your needs. - -Custom template must be on the classpath in `templates/plantuml` directory and must use `.txt` extension. Next -template is set on `WorkflowDiagram` instance as shown below. - -``` java -Workflow workflow = Workflow.fromSource(source); - -WorkflowDiagram workflowDiagram = new WorkflowDiagramImpl(); -workflowDiagram.setWorkflow(workflow); -workflowDiagram.setTemplate("custom-template"); - -String diagramSVG = workflowDiagram.getSvgDiagram(); -``` +#### Writing a workflow -By default the diagram legend is now shown. If you want to enable it you can do: +Given a workflow definition, you can store it using JSON or YAML format. +For example, to store a workflow using json format in a file called `simple.json`, you write ``` java -Workflow workflow = Workflow.fromSource(source); - -WorkflowDiagram workflowDiagram = new WorkflowDiagramImpl(); -workflowDiagram.setWorkflow(workflow) - .showLegend(true); - -String diagramSVG = workflowDiagram.getSvgDiagram(); -``` - -Here are some generated diagrams from the specification examples (with legend enabled): - -1. [Job Monitoring Example](https://github.com/serverlessworkflow/specification/blob/master/examples/examples.md#Monitor-Job-Example) -

-Job Monitoring Example Diagram -

- - -2. [Send CloudEvent on Workflow completion Example](https://github.com/serverlessworkflow/specification/blob/master/examples/examples.md#send-cloudevent-on-workfow-completion-example) -

-Send Cloud Event on Workflow completion -

- -#### Using Workflow Utils -Workflow utils provide a number of useful methods for extracting information from workflow definitions. -Once you have a `Workflow` instance, you can use it -##### Get Starting State -```Java -State startingState = WorkflowUtils.getStartingState(workflow); -``` -##### Get States by State Type -```Java - List states = WorkflowUtils.getStates(workflow, DefaultState.Type.EVENT); -``` -##### Get Consumed-Events, Produced-Events and their count -```Java - List consumedEvents = WorkflowUtils.getWorkflowConsumedEvents(workflow); - int consumedEventsCount = WorkflowUtils.getWorkflowConsumedEventsCount(workflow); - - List producedEvents = WorkflowUtils.getWorkflowProducedEvents(workflow); - int producedEventsCount = WorkflowUtils.getWorkflowProducedEventsCount(workflow); - ``` -##### Get Defined Consumed-Events, Defined Produced-Events and their count -```Java - List consumedEvents = WorkflowUtils.getWorkflowConsumedEventsCount(workflow); - int consumedEventsCount = WorkflowUtils.getWorkflowConsumedEventsCount(workflow); - - List producedEvents = WorkflowUtils.getWorkflowProducedEvents(workflow); - int producedEventsCount = WorkflowUtils.getWorkflowProducedEventsCount(workflow); - ``` -##### Get Function definitions which is used by an action -```Java -FunctionDefinition finalizeApplicationFunctionDefinition = - WorkflowUtils.getFunctionDefinitionsForAction(workflow, "finalizeApplicationAction"); -``` -##### Get Actions which uses a Function definition -```Java - List actionsForFunctionDefinition = - WorkflowUtils.getActionsForFunctionDefinition(workflow, functionRefName); -``` - -#### Extra - -SDK includes extra functionalities which are not part of core modules but -are very useful and can be used as addons to the core: - -##### Diagram REST -This is a Spring Boot app which builds a rest api for diagram generation. -It was contributed by our community member David Marques. - -To start using it: - -``` -cd diagram-rest -mvn clean install spring-boot:run -``` - -Then you can get the diagram SVG for a workflow definition for example: - -``` -curl -X POST localhost:8090/diagram -d '{"id":"booklending","name":"Book Lending Workflow","version":"1.0","specVersion":"0.8","start":"Book Lending Request","states":[{"name":"Book Lending Request","type":"event","onEvents":[{"eventRefs":["Book Lending Request Event"]}],"transition":"Get Book Status"},{"name":"Get Book Status","type":"operation","actions":[{"functionRef":{"refName":"Get status for book","arguments":{"bookid":"${ .book.id }"}}}],"transition":"Book Status Decision"},{"name":"Book Status Decision","type":"switch","dataConditions":[{"name":"Book is on loan","condition":"${ .book.status == \"onloan\" }","transition":"Report Status To Lender"},{"name":"Check is available","condition":"${ .book.status == \"available\" }","transition":"Check Out Book"}]},{"name":"Report Status To Lender","type":"operation","actions":[{"functionRef":{"refName":"Send status to lender","arguments":{"bookid":"${ .book.id }","message":"Book ${ .book.title } is already on loan"}}}],"transition":"Wait for Lender response"},{"name":"Wait for Lender response","type":"switch","eventConditions":[{"name":"Hold Book","eventRef":"Hold Book Event","transition":"Request Hold"},{"name":"Decline Book Hold","eventRef":"Decline Hold Event","transition":"Cancel Request"}]},{"name":"Request Hold","type":"operation","actions":[{"functionRef":{"refName":"Request hold for lender","arguments":{"bookid":"${ .book.id }","lender":"${ .lender }"}}}],"transition":"Wait two weeks"},{"name":"Wait two weeks","type":"sleep","duration":"P2W","transition":"Get Book Status"},{"name":"Check Out Book","type":"operation","actions":[{"functionRef":{"refName":"Check out book with id","arguments":{"bookid":"${ .book.id }"}}},{"functionRef":{"refName":"Notify Lender for checkout","arguments":{"bookid":"${ .book.id }","lender":"${ .lender }"}}}],"end":true}],"functions":[],"events":[]}' -``` - +try (OutputStream out = new FileOutputStream("simple.json")) { + WorkflowWriter.writeWorkflow(out, workflow, WorkflowFormat.JSON); +} +``` \ No newline at end of file diff --git a/api/.gitignore b/api/.gitignore index d4dfde66..c7d1122c 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -28,4 +28,5 @@ target/ build/ ### VS Code ### -.vscode/ \ No newline at end of file +.vscode/ +/.checkstyle diff --git a/api/pom.xml b/api/pom.xml index 9511a191..06547db2 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -17,10 +17,6 @@ org.slf4j slf4j-api - - org.slf4j - jcl-over-slf4j - com.fasterxml.jackson.core jackson-core @@ -37,6 +33,7 @@ jakarta.validation jakarta.validation-api + org.junit.jupiter @@ -77,13 +74,18 @@ org.jsonschema2pojo jsonschema2pojo-maven-plugin - ${basedir}/src/main/resources/schema + ${basedir}/src/main/resources/schema + + + yamlschema io.serverlessworkflow.api.types ${project.build.directory}/generated-sources/src/main/java true true - false - false + true + true false false true @@ -92,7 +94,15 @@ ${java.version} true true + io.serverlessworkflow.generator.UnreferencedFactory + + + io.serverlessworkflow + custom-generator + ${project.version} + + diff --git a/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java new file mode 100644 index 00000000..7bc8414e --- /dev/null +++ b/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature; + +class ObjectMapperFactory { + + private static final ObjectMapper jsonMapper = configure(new ObjectMapper()); + + private static final ObjectMapper yamlMapper = + configure(new ObjectMapper(new YAMLFactory().enable(Feature.MINIMIZE_QUOTES))); + + public static final ObjectMapper jsonMapper() { + return jsonMapper; + } + + public static final ObjectMapper yamlMapper() { + return yamlMapper; + } + + private static ObjectMapper configure(ObjectMapper mapper) { + return mapper + .configure(SerializationFeature.INDENT_OUTPUT, true) + .configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false) + .configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false); + } + + private ObjectMapperFactory() {} +} diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/WorkflowFormat.java similarity index 54% rename from api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapperFactory.java rename to api/src/main/java/io/serverlessworkflow/api/WorkflowFormat.java index eb34b0eb..d0cdfd95 100644 --- a/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapperFactory.java +++ b/api/src/main/java/io/serverlessworkflow/api/WorkflowFormat.java @@ -13,15 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.serverlessworkflow.api.mapper; +package io.serverlessworkflow.api; import com.fasterxml.jackson.databind.ObjectMapper; +import java.nio.file.Path; -public class JsonObjectMapperFactory { +public enum WorkflowFormat { + JSON(ObjectMapperFactory.jsonMapper()), + YAML(ObjectMapperFactory.yamlMapper()); - private static final ObjectMapper instance = new JsonObjectMapper(); + private final ObjectMapper mapper; - public static final ObjectMapper mapper() { - return instance; + public static WorkflowFormat fromPath(Path path) { + return fromFileName(path.getFileName().toString()); + } + + public static WorkflowFormat fromFileName(String fileName) { + return fileName.endsWith(".json") ? JSON : YAML; + } + + private WorkflowFormat(ObjectMapper mapper) { + this.mapper = mapper; + } + + public ObjectMapper mapper() { + return mapper; } } diff --git a/api/src/main/java/io/serverlessworkflow/api/WorkflowReader.java b/api/src/main/java/io/serverlessworkflow/api/WorkflowReader.java new file mode 100644 index 00000000..01c6c8b0 --- /dev/null +++ b/api/src/main/java/io/serverlessworkflow/api/WorkflowReader.java @@ -0,0 +1,58 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import io.serverlessworkflow.api.types.Workflow; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; + +public class WorkflowReader { + + public static Workflow readWorkflow(InputStream input, WorkflowFormat format) throws IOException { + return format.mapper().readValue(input, Workflow.class); + } + + public static Workflow readWorkflow(Reader input, WorkflowFormat format) throws IOException { + return format.mapper().readValue(input, Workflow.class); + } + + public static Workflow readWorkflow(Path path, WorkflowFormat format) throws IOException { + return format.mapper().readValue(Files.readAllBytes(path), Workflow.class); + } + + public static Workflow readWorkflowFromClasspath(String classpath) throws IOException { + return readWorkflowFromClasspath( + classpath, + Thread.currentThread().getContextClassLoader(), + WorkflowFormat.fromFileName(classpath)); + } + + public static Workflow readWorkflowFromClasspath( + String classpath, ClassLoader cl, WorkflowFormat format) throws IOException { + try (InputStream in = cl.getResourceAsStream(classpath)) { + if (in == null) { + throw new FileNotFoundException(classpath); + } + return readWorkflow(in, format); + } + } + + private WorkflowReader() {} +} diff --git a/api/src/main/java/io/serverlessworkflow/api/WorkflowWriter.java b/api/src/main/java/io/serverlessworkflow/api/WorkflowWriter.java new file mode 100644 index 00000000..f98e6402 --- /dev/null +++ b/api/src/main/java/io/serverlessworkflow/api/WorkflowWriter.java @@ -0,0 +1,49 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import io.serverlessworkflow.api.types.Workflow; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; + +public class WorkflowWriter { + + public static void writeWorkflow(OutputStream output, Workflow workflow, WorkflowFormat format) + throws IOException { + format.mapper().writeValue(output, workflow); + } + + public static void writeWorkflow(Writer output, Workflow workflow, WorkflowFormat format) + throws IOException { + format.mapper().writeValue(output, workflow); + } + + public static void writeWorkflow(Path output, Workflow workflow) throws IOException { + writeWorkflow(output, workflow, WorkflowFormat.fromPath(output)); + } + + public static void writeWorkflow(Path output, Workflow workflow, WorkflowFormat format) + throws IOException { + try (OutputStream out = Files.newOutputStream(output)) { + writeWorkflow(out, workflow, format); + } + } + + private WorkflowWriter() {} +} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDefinitionDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDefinitionDeserializer.java deleted file mode 100644 index 01ec3f6e..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDefinitionDeserializer.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.auth.AuthDefinition; -import io.serverlessworkflow.api.auth.BasicAuthDefinition; -import io.serverlessworkflow.api.auth.BearerAuthDefinition; -import io.serverlessworkflow.api.auth.OauthDefinition; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.io.IOException; - -public class AuthDefinitionDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public AuthDefinitionDeserializer() { - this(AuthDefinition.class); - } - - public AuthDefinitionDeserializer(Class vc) { - super(vc); - } - - public AuthDefinitionDeserializer(WorkflowPropertySource context) { - this(AuthDefinition.class); - this.context = context; - } - - @Override - public AuthDefinition deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - AuthDefinition authDefinition = new AuthDefinition(); - - if (node.get("name") != null) { - authDefinition.setName(node.get("name").asText()); - } - - if (node.get("scheme") != null) { - authDefinition.setScheme(AuthDefinition.Scheme.fromValue(node.get("scheme").asText())); - } - - if (node.get("properties") != null) { - JsonNode propsNode = node.get("properties"); - - if (propsNode.get("grantType") != null) { - authDefinition.setOauth(mapper.treeToValue(propsNode, OauthDefinition.class)); - } else if (propsNode.get("token") != null) { - authDefinition.setBearerauth(mapper.treeToValue(propsNode, BearerAuthDefinition.class)); - } else { - authDefinition.setBasicauth(mapper.treeToValue(propsNode, BasicAuthDefinition.class)); - } - } - - return authDefinition; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java deleted file mode 100644 index aa078cb4..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.auth.AuthDefinition; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.utils.Utils; -import io.serverlessworkflow.api.workflow.Auth; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AuthDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 520L; - private static Logger logger = LoggerFactory.getLogger(AuthDeserializer.class); - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public AuthDeserializer() { - this(Auth.class); - } - - public AuthDeserializer(Class vc) { - super(vc); - } - - public AuthDeserializer(WorkflowPropertySource context) { - this(Auth.class); - this.context = context; - } - - @Override - public Auth deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - Auth auth = new Auth(); - List authDefinitions = new ArrayList<>(); - - if (node.isArray()) { - for (final JsonNode nodeEle : node) { - authDefinitions.add(mapper.treeToValue(nodeEle, AuthDefinition.class)); - } - } else { - String authFileDef = node.asText(); - String authFileSrc = Utils.getResourceFileAsString(authFileDef); - if (authFileSrc != null && authFileSrc.trim().length() > 0) { - JsonNode authRefNode = Utils.getNode(authFileSrc); - JsonNode refAuth = authRefNode.get("auth"); - if (refAuth != null) { - for (final JsonNode nodeEle : refAuth) { - authDefinitions.add(mapper.treeToValue(nodeEle, AuthDefinition.class)); - } - } else { - logger.error("Unable to find auth definitions in reference file: {}", authFileSrc); - } - - } else { - logger.error("Unable to load auth defs reference file: {}", authFileSrc); - } - } - auth.setAuthDefs(authDefinitions); - return auth; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java deleted file mode 100644 index 1d95216f..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.utils.Utils; -import io.serverlessworkflow.api.workflow.Constants; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ConstantsDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(ConstantsDeserializer.class); - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public ConstantsDeserializer() { - this(Constants.class); - } - - public ConstantsDeserializer(Class vc) { - super(vc); - } - - public ConstantsDeserializer(WorkflowPropertySource context) { - this(Constants.class); - this.context = context; - } - - @Override - public Constants deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - JsonNode node = jp.getCodec().readTree(jp); - - Constants constants = new Constants(); - JsonNode constantsDefinition = null; - - if (node.isObject()) { - constantsDefinition = node; - } else { - String constantsFileDef = node.asText(); - constants.setRefValue(constantsFileDef); - String constantsFileSrc = Utils.getResourceFileAsString(constantsFileDef); - if (constantsFileSrc != null && constantsFileSrc.trim().length() > 0) { - JsonNode constantsRefNode = Utils.getNode(constantsFileSrc); - JsonNode refConstants = constantsRefNode.get("constants"); - if (refConstants != null) { - constantsDefinition = refConstants; - } else { - logger.error( - "Unable to find constants definitions in reference file: {}", constantsFileSrc); - } - - } else { - logger.error("Unable to load constants defs reference file: {}", constantsFileSrc); - } - } - constants.setConstantsDef(constantsDefinition); - return constants; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ContinueAsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ContinueAsDeserializer.java deleted file mode 100644 index accb1bd3..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ContinueAsDeserializer.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.end.ContinueAs; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.timeouts.WorkflowExecTimeout; -import java.io.IOException; - -public class ContinueAsDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public ContinueAsDeserializer() { - this(ContinueAs.class); - } - - public ContinueAsDeserializer(Class vc) { - super(vc); - } - - public ContinueAsDeserializer(WorkflowPropertySource context) { - this(ContinueAs.class); - this.context = context; - } - - @Override - public ContinueAs deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - ContinueAs continueAs = new ContinueAs(); - - if (!node.isObject()) { - continueAs.setWorkflowId(node.asText()); - continueAs.setVersion(null); - continueAs.setData(null); - continueAs.setWorkflowExecTimeout(null); - return continueAs; - } else { - if (node.get("workflowId") != null) { - continueAs.setWorkflowId(node.get("workflowId").asText()); - } - - if (node.get("version") != null) { - continueAs.setVersion(node.get("version").asText()); - } - - if (node.get("data") != null) { - continueAs.setData(node.get("data").asText()); - } - - if (node.get("workflowExecTimeout") != null) { - continueAs.setWorkflowExecTimeout( - mapper.treeToValue(node.get("workflowExecTimeout"), WorkflowExecTimeout.class)); - } - - return continueAs; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/CronDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/CronDeserializer.java deleted file mode 100644 index 94aa2598..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/CronDeserializer.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.cron.Cron; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.io.IOException; - -public class CronDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public CronDeserializer() { - this(Cron.class); - } - - public CronDeserializer(Class vc) { - super(vc); - } - - public CronDeserializer(WorkflowPropertySource context) { - this(Cron.class); - this.context = context; - } - - @Override - public Cron deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - JsonNode node = jp.getCodec().readTree(jp); - - Cron cron = new Cron(); - - if (!node.isObject()) { - cron.setExpression(node.asText()); - return cron; - } else { - if (node.get("expression") != null) { - cron.setExpression(node.get("expression").asText()); - } - - if (node.get("validUntil") != null) { - cron.setValidUntil(node.get("validUntil").asText()); - } - - return cron; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/DataInputSchemaDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/DataInputSchemaDeserializer.java deleted file mode 100644 index ad711b98..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/DataInputSchemaDeserializer.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.workflow.DataInputSchema; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DataInputSchemaDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(DataInputSchemaDeserializer.class); - - public DataInputSchemaDeserializer() { - this(DataInputSchema.class); - } - - public DataInputSchemaDeserializer(Class vc) { - super(vc); - } - - public DataInputSchemaDeserializer(WorkflowPropertySource context) { - this(DataInputSchema.class); - } - - @Override - public DataInputSchema deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException { - - JsonNode node = jp.getCodec().readTree(jp); - - DataInputSchema dataInputSchema = new DataInputSchema(); - JsonNode schemaDefinition = null; - - if (node.isObject() && node.get("schema").isObject() && !node.get("schema").isEmpty()) { - schemaDefinition = node.get("schema"); - dataInputSchema.setFailOnValidationErrors(node.get("failOnValidationErrors").asBoolean()); - dataInputSchema.setSchemaDef(schemaDefinition); - } else { - String schemaFileDef = node.isObject() ? node.get("schema").asText() : node.asText(); - dataInputSchema.setFailOnValidationErrors(true); - dataInputSchema.setRefValue(schemaFileDef); - } - return dataInputSchema; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/DefaultStateTypeDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/DefaultStateTypeDeserializer.java deleted file mode 100644 index c38a4b47..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/DefaultStateTypeDeserializer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.states.DefaultState; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DefaultStateTypeDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(DefaultStateTypeDeserializer.class); - - private WorkflowPropertySource context; - - public DefaultStateTypeDeserializer() { - this(DefaultState.Type.class); - } - - public DefaultStateTypeDeserializer(WorkflowPropertySource context) { - this(DefaultState.Type.class); - this.context = context; - } - - public DefaultStateTypeDeserializer(Class vc) { - super(vc); - } - - @Override - public DefaultState.Type deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException { - - String value = jp.getText(); - - if (context != null) { - try { - String result = context.getPropertySource().getProperty(value); - - if (result != null) { - return DefaultState.Type.fromValue(result); - } else { - return DefaultState.Type.fromValue(jp.getText()); - } - } catch (Exception e) { - logger.info("Exception trying to evaluate property: {}", e.getMessage()); - return DefaultState.Type.fromValue(jp.getText()); - } - } else { - return DefaultState.Type.fromValue(jp.getText()); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/EndDefinitionDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/EndDefinitionDeserializer.java deleted file mode 100644 index 3a66816b..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/EndDefinitionDeserializer.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.end.ContinueAs; -import io.serverlessworkflow.api.end.End; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.produce.ProduceEvent; -import io.serverlessworkflow.api.start.Start; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class EndDefinitionDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public EndDefinitionDeserializer() { - this(End.class); - } - - public EndDefinitionDeserializer(Class vc) { - super(vc); - } - - public EndDefinitionDeserializer(WorkflowPropertySource context) { - this(Start.class); - this.context = context; - } - - @Override - public End deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - End end = new End(); - - if (node.isBoolean()) { - end.setProduceEvents(null); - end.setCompensate(false); - end.setTerminate(false); - end.setContinueAs(null); - return node.asBoolean() ? end : null; - } else { - if (node.get("produceEvents") != null) { - List produceEvents = new ArrayList<>(); - for (final JsonNode nodeEle : node.get("produceEvents")) { - produceEvents.add(mapper.treeToValue(nodeEle, ProduceEvent.class)); - } - end.setProduceEvents(produceEvents); - } - - if (node.get("terminate") != null) { - end.setTerminate(node.get("terminate").asBoolean()); - } else { - end.setTerminate(false); - } - - if (node.get("compensate") != null) { - end.setCompensate(node.get("compensate").asBoolean()); - } else { - end.setCompensate(false); - } - - if (node.get("continueAs") != null) { - end.setContinueAs(mapper.treeToValue(node.get("continueAs"), ContinueAs.class)); - } - - return end; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java deleted file mode 100644 index 6fe366ea..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.error.ErrorDefinition; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.utils.Utils; -import io.serverlessworkflow.api.workflow.Errors; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ErrorsDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(ErrorsDeserializer.class); - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public ErrorsDeserializer() { - this(Errors.class); - } - - public ErrorsDeserializer(Class vc) { - super(vc); - } - - public ErrorsDeserializer(WorkflowPropertySource context) { - this(Errors.class); - this.context = context; - } - - @Override - public Errors deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - Errors errors = new Errors(); - List errorDefinitions = new ArrayList<>(); - - if (node.isArray()) { - for (final JsonNode nodeEle : node) { - errorDefinitions.add(mapper.treeToValue(nodeEle, ErrorDefinition.class)); - } - } else { - String errorsFileDef = node.asText(); - String errorsFileSrc = Utils.getResourceFileAsString(errorsFileDef); - if (errorsFileSrc != null && errorsFileSrc.trim().length() > 0) { - JsonNode errorsRefNode = Utils.getNode(errorsFileSrc); - JsonNode refErrors = errorsRefNode.get("errors"); - if (refErrors != null) { - for (final JsonNode nodeEle : refErrors) { - errorDefinitions.add(mapper.treeToValue(nodeEle, ErrorDefinition.class)); - } - } else { - logger.error("Unable to find error definitions in reference file: {}", errorsFileSrc); - } - - } else { - logger.error("Unable to load errors defs reference file: {}", errorsFileSrc); - } - } - errors.setErrorDefs(errorDefinitions); - return errors; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/EventDefinitionKindDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/EventDefinitionKindDeserializer.java deleted file mode 100644 index b9ee25b3..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/EventDefinitionKindDeserializer.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EventDefinitionKindDeserializer extends StdDeserializer { - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(EventDefinitionKindDeserializer.class); - - private WorkflowPropertySource context; - - public EventDefinitionKindDeserializer() { - this(EventDefinition.Kind.class); - } - - public EventDefinitionKindDeserializer(WorkflowPropertySource context) { - this(EventDefinition.Kind.class); - this.context = context; - } - - public EventDefinitionKindDeserializer(Class vc) { - super(vc); - } - - @Override - public EventDefinition.Kind deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException { - - String value = jp.getText(); - if (context != null) { - try { - String result = context.getPropertySource().getProperty(value); - - if (result != null) { - return EventDefinition.Kind.fromValue(result); - } else { - return EventDefinition.Kind.fromValue(jp.getText()); - } - } catch (Exception e) { - logger.info("Exception trying to evaluate property: {}", e.getMessage()); - return EventDefinition.Kind.fromValue(jp.getText()); - } - } else { - return EventDefinition.Kind.fromValue(jp.getText()); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java deleted file mode 100644 index a02fdf4b..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.utils.Utils; -import io.serverlessworkflow.api.workflow.Events; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EventsDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(EventsDeserializer.class); - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public EventsDeserializer() { - this(Events.class); - } - - public EventsDeserializer(Class vc) { - super(vc); - } - - public EventsDeserializer(WorkflowPropertySource context) { - this(Events.class); - this.context = context; - } - - @Override - public Events deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - Events events = new Events(); - List eventDefs = new ArrayList<>(); - - if (node.isArray()) { - for (final JsonNode nodeEle : node) { - eventDefs.add(mapper.treeToValue(nodeEle, EventDefinition.class)); - } - } else { - String eventsFileDef = node.asText(); - String eventsFileSrc = Utils.getResourceFileAsString(eventsFileDef); - if (eventsFileSrc != null && eventsFileSrc.trim().length() > 0) { - // if its a yaml def convert to json first - JsonNode eventsRefNode = Utils.getNode(eventsFileSrc); - JsonNode refEvents = eventsRefNode.get("events"); - if (refEvents != null) { - for (final JsonNode nodeEle : refEvents) { - eventDefs.add(mapper.treeToValue(nodeEle, EventDefinition.class)); - } - } else { - logger.error("Unable to find event definitions in reference file: {}", eventsFileSrc); - } - - } else { - logger.error("Unable to load event defs reference file: {}", eventsFileSrc); - } - } - events.setEventDefs(eventDefs); - return events; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ExtensionDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ExtensionDeserializer.java deleted file mode 100644 index c5c6be21..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ExtensionDeserializer.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.Extension; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ExtensionDeserializer extends StdDeserializer { - - private WorkflowPropertySource context; - private Map> extensionsMap = new HashMap<>(); - private static Logger logger = LoggerFactory.getLogger(ExtensionDeserializer.class); - - public ExtensionDeserializer() { - this(Extension.class); - } - - public ExtensionDeserializer(Class vc) { - super(vc); - } - - public ExtensionDeserializer(WorkflowPropertySource context) { - this(Extension.class); - this.context = context; - } - - public void addExtension(String extensionId, Class extensionClass) { - this.extensionsMap.put(extensionId, extensionClass); - } - - @Override - public Extension deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - String extensionId = node.get("extensionId").asText(); - - if (context != null) { - try { - String result = context.getPropertySource().getProperty(extensionId); - - if (result != null) { - extensionId = result; - } - } catch (Exception e) { - logger.info("Exception trying to evaluate property: {}", e.getMessage()); - } - } - - // based on the name return the specific extension impl - if (extensionsMap != null && extensionsMap.containsKey(extensionId)) { - return mapper.treeToValue(node, extensionsMap.get(extensionId)); - } else { - throw new IllegalArgumentException("Extension handler not registered for: " + extensionId); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionDefinitionTypeDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionDefinitionTypeDeserializer.java deleted file mode 100644 index e8cd54a3..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionDefinitionTypeDeserializer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FunctionDefinitionTypeDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(FunctionDefinitionTypeDeserializer.class); - - private WorkflowPropertySource context; - - public FunctionDefinitionTypeDeserializer() { - this(FunctionDefinition.Type.class); - } - - public FunctionDefinitionTypeDeserializer(WorkflowPropertySource context) { - this(FunctionDefinition.Type.class); - this.context = context; - } - - public FunctionDefinitionTypeDeserializer(Class vc) { - super(vc); - } - - @Override - public FunctionDefinition.Type deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException { - - String value = jp.getText(); - if (context != null) { - try { - String result = context.getPropertySource().getProperty(value); - - if (result != null) { - return FunctionDefinition.Type.fromValue(result); - } else { - return FunctionDefinition.Type.fromValue(jp.getText()); - } - } catch (Exception e) { - logger.info("Exception trying to evaluate property: {}", e.getMessage()); - return FunctionDefinition.Type.fromValue(jp.getText()); - } - } else { - return FunctionDefinition.Type.fromValue(jp.getText()); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionRefDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionRefDeserializer.java deleted file mode 100644 index 8204b7bc..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionRefDeserializer.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.functions.FunctionRef; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.io.IOException; - -public class FunctionRefDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public FunctionRefDeserializer() { - this(FunctionRef.class); - } - - public FunctionRefDeserializer(Class vc) { - super(vc); - } - - public FunctionRefDeserializer(WorkflowPropertySource context) { - this(FunctionRef.class); - this.context = context; - } - - @Override - public FunctionRef deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - FunctionRef functionRef = new FunctionRef(); - - if (!node.isObject()) { - functionRef.setRefName(node.asText()); - functionRef.setArguments(null); - functionRef.setInvoke(FunctionRef.Invoke.SYNC); - return functionRef; - } else { - if (node.get("arguments") != null) { - functionRef.setArguments(mapper.treeToValue(node.get("arguments"), JsonNode.class)); - } - - if (node.get("refName") != null) { - functionRef.setRefName(node.get("refName").asText()); - } - - if (node.get("selectionSet") != null) { - functionRef.setSelectionSet(node.get("selectionSet").asText()); - } - - if (node.get("invoke") != null) { - functionRef.setInvoke(FunctionRef.Invoke.fromValue(node.get("invoke").asText())); - } - - return functionRef; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java deleted file mode 100644 index b706b2d3..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.utils.Utils; -import io.serverlessworkflow.api.workflow.Functions; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FunctionsDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(FunctionsDeserializer.class); - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public FunctionsDeserializer() { - this(Functions.class); - } - - public FunctionsDeserializer(Class vc) { - super(vc); - } - - public FunctionsDeserializer(WorkflowPropertySource context) { - this(Functions.class); - this.context = context; - } - - @Override - public Functions deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - Functions functions = new Functions(); - List functionDefs = new ArrayList<>(); - if (node.isArray()) { - for (final JsonNode nodeEle : node) { - functionDefs.add(mapper.treeToValue(nodeEle, FunctionDefinition.class)); - } - } else { - String functionsFileDef = node.asText(); - String functionsFileSrc = Utils.getResourceFileAsString(functionsFileDef); - JsonNode functionsRefNode; - if (functionsFileSrc != null && functionsFileSrc.trim().length() > 0) { - // if its a yaml def convert to json first - functionsRefNode = Utils.getNode(functionsFileSrc); - JsonNode refFunctions = functionsRefNode.get("functions"); - if (refFunctions != null) { - for (final JsonNode nodeEle : refFunctions) { - functionDefs.add(mapper.treeToValue(nodeEle, FunctionDefinition.class)); - } - } else { - logger.error( - "Unable to find function definitions in reference file: {}", functionsFileSrc); - } - - } else { - logger.error("Unable to load function defs reference file: {}", functionsFileSrc); - } - } - functions.setFunctionDefs(functionDefs); - return functions; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/OnEventsActionModeDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/OnEventsActionModeDeserializer.java deleted file mode 100644 index f98b8a23..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/OnEventsActionModeDeserializer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.events.OnEvents; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class OnEventsActionModeDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(OnEventsActionModeDeserializer.class); - - private WorkflowPropertySource context; - - public OnEventsActionModeDeserializer() { - this(OnEvents.ActionMode.class); - } - - public OnEventsActionModeDeserializer(WorkflowPropertySource context) { - this(OnEvents.ActionMode.class); - this.context = context; - } - - public OnEventsActionModeDeserializer(Class vc) { - super(vc); - } - - @Override - public OnEvents.ActionMode deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException { - - String value = jp.getText(); - if (context != null) { - try { - String result = context.getPropertySource().getProperty(value); - - if (result != null) { - return OnEvents.ActionMode.fromValue(result); - } else { - return OnEvents.ActionMode.fromValue(jp.getText()); - } - } catch (Exception e) { - logger.info("Exception trying to evaluate property: {}", e.getMessage()); - return OnEvents.ActionMode.fromValue(jp.getText()); - } - } else { - return OnEvents.ActionMode.fromValue(jp.getText()); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/OperationStateActionModeDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/OperationStateActionModeDeserializer.java deleted file mode 100644 index ffad4ea0..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/OperationStateActionModeDeserializer.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.states.OperationState; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class OperationStateActionModeDeserializer - extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = - LoggerFactory.getLogger(OperationStateActionModeDeserializer.class); - - private WorkflowPropertySource context; - - public OperationStateActionModeDeserializer() { - this(OperationState.ActionMode.class); - } - - public OperationStateActionModeDeserializer(WorkflowPropertySource context) { - this(OperationState.ActionMode.class); - this.context = context; - } - - public OperationStateActionModeDeserializer(Class vc) { - super(vc); - } - - @Override - public OperationState.ActionMode deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException { - - String value = jp.getText(); - if (context != null) { - try { - String result = context.getPropertySource().getProperty(value); - - if (result != null) { - return OperationState.ActionMode.fromValue(result); - } else { - return OperationState.ActionMode.fromValue(jp.getText()); - } - } catch (Exception e) { - logger.info("Exception trying to evaluate property: {}", e.getMessage()); - return OperationState.ActionMode.fromValue(jp.getText()); - } - } else { - return OperationState.ActionMode.fromValue(jp.getText()); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ParallelStateCompletionTypeDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ParallelStateCompletionTypeDeserializer.java deleted file mode 100644 index 281fd486..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ParallelStateCompletionTypeDeserializer.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.states.ParallelState; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ParallelStateCompletionTypeDeserializer - extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = - LoggerFactory.getLogger(ParallelStateCompletionTypeDeserializer.class); - - private WorkflowPropertySource context; - - public ParallelStateCompletionTypeDeserializer() { - this(ParallelState.CompletionType.class); - } - - public ParallelStateCompletionTypeDeserializer(WorkflowPropertySource context) { - this(ParallelState.CompletionType.class); - this.context = context; - } - - public ParallelStateCompletionTypeDeserializer(Class vc) { - super(vc); - } - - @Override - public ParallelState.CompletionType deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException { - - String value = jp.getText(); - if (context != null) { - try { - String result = context.getPropertySource().getProperty(value); - - if (result != null) { - return ParallelState.CompletionType.fromValue(result); - } else { - return ParallelState.CompletionType.fromValue(jp.getText()); - } - } catch (Exception e) { - logger.info("Exception trying to evaluate property: {}", e.getMessage()); - return ParallelState.CompletionType.fromValue(jp.getText()); - } - } else { - return ParallelState.CompletionType.fromValue(jp.getText()); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java deleted file mode 100644 index 9eb47b5f..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.retry.RetryDefinition; -import io.serverlessworkflow.api.utils.Utils; -import io.serverlessworkflow.api.workflow.Retries; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RetriesDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(RetriesDeserializer.class); - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public RetriesDeserializer() { - this(Retries.class); - } - - public RetriesDeserializer(Class vc) { - super(vc); - } - - public RetriesDeserializer(WorkflowPropertySource context) { - this(Retries.class); - this.context = context; - } - - @Override - public Retries deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - Retries retries = new Retries(); - List retryDefinitions = new ArrayList<>(); - - if (node.isArray()) { - for (final JsonNode nodeEle : node) { - retryDefinitions.add(mapper.treeToValue(nodeEle, RetryDefinition.class)); - } - } else { - String retriesFileDef = node.asText(); - String retriesFileSrc = Utils.getResourceFileAsString(retriesFileDef); - if (retriesFileSrc != null && retriesFileSrc.trim().length() > 0) { - JsonNode retriesRefNode = Utils.getNode(retriesFileSrc); - JsonNode refRetries = retriesRefNode.get("retries"); - if (refRetries != null) { - for (final JsonNode nodeEle : refRetries) { - retryDefinitions.add(mapper.treeToValue(nodeEle, RetryDefinition.class)); - } - } else { - logger.error("Unable to find retries definitions in reference file: {}", retriesFileSrc); - } - - } else { - logger.error("Unable to load retries defs reference file: {}", retriesFileSrc); - } - } - retries.setRetryDefs(retryDefinitions); - return retries; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ScheduleDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ScheduleDeserializer.java deleted file mode 100644 index b6bc5359..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ScheduleDeserializer.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.cron.Cron; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.schedule.Schedule; -import java.io.IOException; - -public class ScheduleDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public ScheduleDeserializer() { - this(Schedule.class); - } - - public ScheduleDeserializer(Class vc) { - super(vc); - } - - public ScheduleDeserializer(WorkflowPropertySource context) { - this(Schedule.class); - this.context = context; - } - - @Override - public Schedule deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - Schedule schedule = new Schedule(); - - if (!node.isObject()) { - schedule.setInterval(node.asText()); - return schedule; - } else { - if (node.get("interval") != null) { - schedule.setInterval(node.get("interval").asText()); - } - - if (node.get("cron") != null) { - schedule.setCron(mapper.treeToValue(node.get("cron"), Cron.class)); - } - - if (node.get("timezone") != null) { - schedule.setTimezone(node.get("timezone").asText()); - } - - return schedule; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java deleted file mode 100644 index 60cc2a82..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.utils.Utils; -import io.serverlessworkflow.api.workflow.Secrets; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SecretsDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(SecretsDeserializer.class); - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public SecretsDeserializer() { - this(Secrets.class); - } - - public SecretsDeserializer(Class vc) { - super(vc); - } - - public SecretsDeserializer(WorkflowPropertySource context) { - this(Secrets.class); - this.context = context; - } - - @Override - public Secrets deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - JsonNode node = jp.getCodec().readTree(jp); - - Secrets secrets = new Secrets(); - List secretsDefinitions = new ArrayList<>(); - - if (node.isArray()) { - for (final JsonNode nodeEle : node) { - secretsDefinitions.add(nodeEle.asText()); - } - } else { - String secretsFileDef = node.asText(); - String secretsFileSrc = Utils.getResourceFileAsString(secretsFileDef); - if (secretsFileSrc != null && secretsFileSrc.trim().length() > 0) { - // if its a yaml def convert to json first - JsonNode secretsRefNode = Utils.getNode(secretsFileSrc); - JsonNode refSecrets = secretsRefNode.get("secrets"); - if (refSecrets != null) { - for (final JsonNode nodeEle : refSecrets) { - secretsDefinitions.add(nodeEle.asText()); - } - } else { - logger.error("Unable to find secrets definitions in reference file: {}", secretsFileSrc); - } - - } else { - logger.error("Unable to load secrets defs reference file: {}", secretsFileSrc); - } - } - secrets.setSecretDefs(secretsDefinitions); - return secrets; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/StartDefinitionDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/StartDefinitionDeserializer.java deleted file mode 100644 index e709a079..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/StartDefinitionDeserializer.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.schedule.Schedule; -import io.serverlessworkflow.api.start.Start; -import java.io.IOException; - -public class StartDefinitionDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public StartDefinitionDeserializer() { - this(Start.class); - } - - public StartDefinitionDeserializer(Class vc) { - super(vc); - } - - public StartDefinitionDeserializer(WorkflowPropertySource context) { - this(Start.class); - this.context = context; - } - - @Override - public Start deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - Start start = new Start(); - - if (!node.isObject()) { - start.setStateName(node.asText()); - start.setSchedule(null); - return start; - } else { - if (node.get("stateName") != null) { - start.setStateName(node.get("stateName").asText()); - } - - if (node.get("schedule") != null) { - start.setSchedule(mapper.treeToValue(node.get("schedule"), Schedule.class)); - } - - return start; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/StateDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/StateDeserializer.java deleted file mode 100644 index 25672c76..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/StateDeserializer.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.states.*; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class StateDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(StateDeserializer.class); - - private WorkflowPropertySource context; - - public StateDeserializer() { - this(State.class); - } - - public StateDeserializer(Class vc) { - super(vc); - } - - public StateDeserializer(WorkflowPropertySource context) { - this(State.class); - this.context = context; - } - - @Override - public State deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - String typeValue = node.get("type").asText(); - - if (context != null) { - try { - String result = context.getPropertySource().getProperty(typeValue); - - if (result != null) { - typeValue = result; - } - } catch (Exception e) { - logger.info("Exception trying to evaluate property: {}", e.getMessage()); - } - } - - // based on statetype return the specific state impl - DefaultState.Type type = DefaultState.Type.fromValue(typeValue); - switch (type) { - case EVENT: - return mapper.treeToValue(node, EventState.class); - case OPERATION: - return mapper.treeToValue(node, OperationState.class); - case SWITCH: - return mapper.treeToValue(node, SwitchState.class); - case SLEEP: - return mapper.treeToValue(node, SleepState.class); - case PARALLEL: - return mapper.treeToValue(node, ParallelState.class); - - case INJECT: - return mapper.treeToValue(node, InjectState.class); - - case FOREACH: - return mapper.treeToValue(node, ForEachState.class); - - case CALLBACK: - return mapper.treeToValue(node, CallbackState.class); - default: - return mapper.treeToValue(node, DefaultState.class); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/StateExecTimeoutDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/StateExecTimeoutDeserializer.java deleted file mode 100644 index 18a73550..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/StateExecTimeoutDeserializer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.timeouts.StateExecTimeout; -import java.io.IOException; - -public class StateExecTimeoutDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public StateExecTimeoutDeserializer() { - this(StateExecTimeout.class); - } - - public StateExecTimeoutDeserializer(Class vc) { - super(vc); - } - - public StateExecTimeoutDeserializer(WorkflowPropertySource context) { - this(StateExecTimeout.class); - this.context = context; - } - - @Override - public StateExecTimeout deserialize(JsonParser jp, DeserializationContext ctxt) - throws IOException { - - JsonNode node = jp.getCodec().readTree(jp); - - StateExecTimeout stateExecTimeout = new StateExecTimeout(); - - if (!node.isObject()) { - stateExecTimeout.setTotal(node.asText()); - stateExecTimeout.setSingle(null); - return stateExecTimeout; - } else { - if (node.get("single") != null) { - stateExecTimeout.setSingle(node.get("single").asText()); - } - - if (node.get("total") != null) { - stateExecTimeout.setTotal(node.get("total").asText()); - } - - return stateExecTimeout; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/StringValueDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/StringValueDeserializer.java deleted file mode 100644 index 7704cdf2..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/StringValueDeserializer.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.io.IOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class StringValueDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - private static Logger logger = LoggerFactory.getLogger(StringValueDeserializer.class); - - private WorkflowPropertySource context; - - public StringValueDeserializer() { - this(String.class); - } - - public StringValueDeserializer(WorkflowPropertySource context) { - this(String.class); - this.context = context; - } - - public StringValueDeserializer(Class vc) { - super(vc); - } - - @Override - public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - String value = jp.getText(); - if (context != null) { - try { - String result = context.getPropertySource().getProperty(value); - - if (result != null) { - return result; - } else { - return jp.getText(); - } - } catch (Exception e) { - logger.info("Exception trying to evaluate property: {}", e.getMessage()); - return jp.getText(); - } - } else { - return jp.getText(); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/SubFlowRefDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/SubFlowRefDeserializer.java deleted file mode 100644 index 53e45969..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/SubFlowRefDeserializer.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.functions.SubFlowRef; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.io.IOException; - -public class SubFlowRefDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public SubFlowRefDeserializer() { - this(SubFlowRef.class); - } - - public SubFlowRefDeserializer(Class vc) { - super(vc); - } - - public SubFlowRefDeserializer(WorkflowPropertySource context) { - this(SubFlowRef.class); - this.context = context; - } - - @Override - public SubFlowRef deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - JsonNode node = jp.getCodec().readTree(jp); - - SubFlowRef subflowRef = new SubFlowRef(); - - if (!node.isObject()) { - subflowRef.setWorkflowId(node.asText()); - return subflowRef; - } else { - if (node.get("workflowId") != null) { - subflowRef.setWorkflowId(node.get("workflowId").asText()); - } - - if (node.get("version") != null) { - subflowRef.setVersion(node.get("version").asText()); - } - - if (node.get("onParentComplete") != null) { - subflowRef.setOnParentComplete( - SubFlowRef.OnParentComplete.fromValue(node.get("onParentComplete").asText())); - } - - if (node.get("invoke") != null) { - subflowRef.setInvoke(SubFlowRef.Invoke.fromValue(node.get("invoke").asText())); - } - - return subflowRef; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/TransitionDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/TransitionDeserializer.java deleted file mode 100644 index 43441434..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/deserializers/TransitionDeserializer.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.deserializers; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.produce.ProduceEvent; -import io.serverlessworkflow.api.transitions.Transition; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; - -public class TransitionDeserializer extends StdDeserializer { - - private static final long serialVersionUID = 510l; - - @SuppressWarnings("unused") - private WorkflowPropertySource context; - - public TransitionDeserializer() { - this(Transition.class); - } - - public TransitionDeserializer(Class vc) { - super(vc); - } - - public TransitionDeserializer(WorkflowPropertySource context) { - this(Transition.class); - this.context = context; - } - - @Override - public Transition deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = jp.getCodec().readTree(jp); - - Transition transition = new Transition(); - - if (!node.isObject()) { - transition.setProduceEvents(new ArrayList<>()); - transition.setCompensate(false); - transition.setNextState(node.asText()); - return transition; - } else { - if (node.get("produceEvents") != null) { - transition.setProduceEvents( - Arrays.asList(mapper.treeToValue(node.get("produceEvents"), ProduceEvent[].class))); - } - - if (node.get("nextState") != null) { - transition.setNextState(node.get("nextState").asText()); - } - - if (node.get("compensate") != null) { - transition.setCompensate(node.get("compensate").asBoolean()); - } - - return transition; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/interfaces/Extension.java b/api/src/main/java/io/serverlessworkflow/api/interfaces/Extension.java deleted file mode 100644 index cb0461f7..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/interfaces/Extension.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.interfaces; - -public interface Extension { - String getExtensionId(); -} diff --git a/api/src/main/java/io/serverlessworkflow/api/interfaces/State.java b/api/src/main/java/io/serverlessworkflow/api/interfaces/State.java deleted file mode 100644 index cdeea8e1..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/interfaces/State.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.interfaces; - -import io.serverlessworkflow.api.end.End; -import io.serverlessworkflow.api.error.Error; -import io.serverlessworkflow.api.filters.StateDataFilter; -import io.serverlessworkflow.api.states.DefaultState.Type; -import io.serverlessworkflow.api.timeouts.TimeoutsDefinition; -import io.serverlessworkflow.api.transitions.Transition; -import java.util.List; -import java.util.Map; - -public interface State { - - String getId(); - - String getName(); - - Type getType(); - - End getEnd(); - - StateDataFilter getStateDataFilter(); - - Transition getTransition(); - - List getOnErrors(); - - String getCompensatedBy(); - - Map getMetadata(); - - TimeoutsDefinition getTimeouts(); -} diff --git a/api/src/main/java/io/serverlessworkflow/api/interfaces/SwitchCondition.java b/api/src/main/java/io/serverlessworkflow/api/interfaces/SwitchCondition.java deleted file mode 100644 index 4a4368de..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/interfaces/SwitchCondition.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.interfaces; - -public interface SwitchCondition {} diff --git a/api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowDiagram.java b/api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowDiagram.java deleted file mode 100644 index 0c62d4d2..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowDiagram.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.interfaces; - -import io.serverlessworkflow.api.Workflow; - -public interface WorkflowDiagram { - WorkflowDiagram setWorkflow(Workflow workflow); - - WorkflowDiagram setSource(String source); - - WorkflowDiagram setTemplate(String template); - - String getSvgDiagram() throws Exception; - - WorkflowDiagram showLegend(boolean showLegend); -} diff --git a/api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowPropertySource.java b/api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowPropertySource.java deleted file mode 100644 index 73b35ac9..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowPropertySource.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.interfaces; - -import java.util.Properties; - -public interface WorkflowPropertySource { - - Properties getPropertySource(); - - void setPropertySource(Properties source); -} diff --git a/api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowValidator.java b/api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowValidator.java deleted file mode 100644 index 199a0927..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/interfaces/WorkflowValidator.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.interfaces; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.validation.ValidationError; -import java.util.List; - -public interface WorkflowValidator { - - WorkflowValidator setWorkflow(Workflow workflow); - - WorkflowValidator setSource(String source); - - List validate(); - - boolean isValid(); - - WorkflowValidator setSchemaValidationEnabled(boolean schemaValidationEnabled); - - WorkflowValidator reset(); -} diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/BaseObjectMapper.java b/api/src/main/java/io/serverlessworkflow/api/mapper/BaseObjectMapper.java deleted file mode 100644 index 2f71947d..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/mapper/BaseObjectMapper.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.mapper; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.util.Map; - -public class BaseObjectMapper extends ObjectMapper { - - private WorkflowModule workflowModule; - - public BaseObjectMapper(JsonFactory factory, WorkflowPropertySource workflowPropertySource) { - super(factory); - - workflowModule = new WorkflowModule(workflowPropertySource); - - configure(SerializationFeature.INDENT_OUTPUT, true); - registerModule(workflowModule); - configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false); - configOverride(Map.class) - .setInclude( - JsonInclude.Value.construct( - JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL)); - } - - public WorkflowModule getWorkflowModule() { - return workflowModule; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapper.java b/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapper.java deleted file mode 100644 index 2480beb0..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapper.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.mapper; - -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; - -public class JsonObjectMapper extends BaseObjectMapper { - - public JsonObjectMapper() { - this(null); - } - - public JsonObjectMapper(WorkflowPropertySource context) { - super(null, context); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/WorkflowModule.java b/api/src/main/java/io/serverlessworkflow/api/mapper/WorkflowModule.java deleted file mode 100644 index 10c12992..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/mapper/WorkflowModule.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.mapper; - -import com.fasterxml.jackson.databind.module.SimpleModule; -import io.serverlessworkflow.api.auth.AuthDefinition; -import io.serverlessworkflow.api.cron.Cron; -import io.serverlessworkflow.api.deserializers.*; -import io.serverlessworkflow.api.end.ContinueAs; -import io.serverlessworkflow.api.end.End; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.api.events.OnEvents; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.functions.FunctionRef; -import io.serverlessworkflow.api.functions.SubFlowRef; -import io.serverlessworkflow.api.interfaces.Extension; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.schedule.Schedule; -import io.serverlessworkflow.api.serializers.*; -import io.serverlessworkflow.api.start.Start; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.api.states.OperationState; -import io.serverlessworkflow.api.states.ParallelState; -import io.serverlessworkflow.api.timeouts.StateExecTimeout; -import io.serverlessworkflow.api.transitions.Transition; -import io.serverlessworkflow.api.workflow.*; - -public class WorkflowModule extends SimpleModule { - - private static final long serialVersionUID = 510l; - - private WorkflowPropertySource workflowPropertySource; - private ExtensionSerializer extensionSerializer; - private ExtensionDeserializer extensionDeserializer; - - public WorkflowModule() { - this(null); - } - - public WorkflowModule(WorkflowPropertySource workflowPropertySource) { - super("workflow-module"); - this.workflowPropertySource = workflowPropertySource; - extensionSerializer = new ExtensionSerializer(); - extensionDeserializer = new ExtensionDeserializer(workflowPropertySource); - addDefaultSerializers(); - addDefaultDeserializers(); - } - - private void addDefaultSerializers() { - addSerializer(new WorkflowSerializer()); - addSerializer(new EventStateSerializer()); - addSerializer(new SleepStateSerializer()); - addSerializer(new OperationStateSerializer()); - addSerializer(new ParallelStateSerializer()); - addSerializer(new SwitchStateSerializer()); - addSerializer(new InjectStateSerializer()); - addSerializer(new ForEachStateSerializer()); - addSerializer(new CallbackStateSerializer()); - addSerializer(new StartDefinitionSerializer()); - addSerializer(new EndDefinitionSerializer()); - addSerializer(new TransitionSerializer()); - addSerializer(new FunctionRefSerializer()); - addSerializer(new CronSerializer()); - addSerializer(new ScheduleSerializer()); - addSerializer(new SubFlowRefSerializer()); - addSerializer(new AuthDefinitionSerializer()); - addSerializer(new StateExecTimeoutSerializer()); - addSerializer(new ContinueAsSerializer()); - addSerializer(extensionSerializer); - } - - private void addDefaultDeserializers() { - addDeserializer(State.class, new StateDeserializer(workflowPropertySource)); - addDeserializer(String.class, new StringValueDeserializer(workflowPropertySource)); - addDeserializer( - OnEvents.ActionMode.class, new OnEventsActionModeDeserializer(workflowPropertySource)); - addDeserializer( - OperationState.ActionMode.class, - new OperationStateActionModeDeserializer(workflowPropertySource)); - addDeserializer( - DefaultState.Type.class, new DefaultStateTypeDeserializer(workflowPropertySource)); - addDeserializer( - EventDefinition.Kind.class, new EventDefinitionKindDeserializer(workflowPropertySource)); - addDeserializer( - ParallelState.CompletionType.class, - new ParallelStateCompletionTypeDeserializer(workflowPropertySource)); - addDeserializer(Retries.class, new RetriesDeserializer(workflowPropertySource)); - addDeserializer(Secrets.class, new SecretsDeserializer(workflowPropertySource)); - addDeserializer(Constants.class, new ConstantsDeserializer(workflowPropertySource)); - addDeserializer(Functions.class, new FunctionsDeserializer(workflowPropertySource)); - addDeserializer(Events.class, new EventsDeserializer(workflowPropertySource)); - addDeserializer(Start.class, new StartDefinitionDeserializer(workflowPropertySource)); - addDeserializer(End.class, new EndDefinitionDeserializer(workflowPropertySource)); - addDeserializer(Extension.class, extensionDeserializer); - addDeserializer( - FunctionDefinition.Type.class, - new FunctionDefinitionTypeDeserializer(workflowPropertySource)); - addDeserializer(Transition.class, new TransitionDeserializer(workflowPropertySource)); - addDeserializer(FunctionRef.class, new FunctionRefDeserializer(workflowPropertySource)); - addDeserializer(SubFlowRef.class, new SubFlowRefDeserializer(workflowPropertySource)); - addDeserializer(Cron.class, new CronDeserializer(workflowPropertySource)); - addDeserializer(Schedule.class, new ScheduleDeserializer(workflowPropertySource)); - addDeserializer(DataInputSchema.class, new DataInputSchemaDeserializer(workflowPropertySource)); - addDeserializer(AuthDefinition.class, new AuthDefinitionDeserializer(workflowPropertySource)); - addDeserializer( - StateExecTimeout.class, new StateExecTimeoutDeserializer(workflowPropertySource)); - addDeserializer(Errors.class, new ErrorsDeserializer(workflowPropertySource)); - addDeserializer(ContinueAs.class, new ContinueAsDeserializer(workflowPropertySource)); - addDeserializer(Auth.class, new AuthDeserializer(workflowPropertySource)); - } - - public ExtensionSerializer getExtensionSerializer() { - return extensionSerializer; - } - - public ExtensionDeserializer getExtensionDeserializer() { - return extensionDeserializer; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapper.java b/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapper.java deleted file mode 100644 index 8e76d217..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapper.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.mapper; - -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature; -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; - -public class YamlObjectMapper extends BaseObjectMapper { - public YamlObjectMapper() { - this(null); - } - - public YamlObjectMapper(WorkflowPropertySource context) { - super(new YAMLFactory().enable(Feature.MINIMIZE_QUOTES), context); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java deleted file mode 100644 index 04371db4..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.mapper; - -import com.fasterxml.jackson.databind.ObjectMapper; - -public class YamlObjectMapperFactory { - - private static final ObjectMapper instance = new YamlObjectMapper(); - - public static final ObjectMapper mapper() { - return instance; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/AuthDefinitionSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/AuthDefinitionSerializer.java deleted file mode 100644 index 827ff075..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/AuthDefinitionSerializer.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.auth.AuthDefinition; -import java.io.IOException; - -public class AuthDefinitionSerializer extends StdSerializer { - - public AuthDefinitionSerializer() { - this(AuthDefinition.class); - } - - protected AuthDefinitionSerializer(Class t) { - super(t); - } - - @Override - public void serialize( - AuthDefinition authDefinition, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - gen.writeStartObject(); - if (authDefinition != null) { - if (authDefinition.getName() != null && !authDefinition.getName().isEmpty()) { - gen.writeStringField("name", authDefinition.getName()); - } - - if (authDefinition.getScheme() != null) { - gen.writeStringField("scheme", authDefinition.getScheme().value()); - } - - if (authDefinition.getBasicauth() != null - || authDefinition.getBearerauth() != null - || authDefinition.getOauth() != null) { - - if (authDefinition.getBasicauth() != null) { - gen.writeObjectField("properties", authDefinition.getBasicauth()); - } - - if (authDefinition.getBearerauth() != null) { - gen.writeObjectField("properties", authDefinition.getBearerauth()); - } - - if (authDefinition.getOauth() != null) { - gen.writeObjectField("properties", authDefinition.getOauth()); - } - } - } - gen.writeEndObject(); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/CallbackStateSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/CallbackStateSerializer.java deleted file mode 100644 index 4e6e0b82..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/CallbackStateSerializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.states.CallbackState; -import io.serverlessworkflow.api.states.DefaultState; -import java.io.IOException; - -public class CallbackStateSerializer extends StdSerializer { - - public CallbackStateSerializer() { - this(CallbackState.class); - } - - protected CallbackStateSerializer(Class t) { - super(t); - } - - @Override - public void serialize(CallbackState callbackState, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - // set defaults for callback state - callbackState.setType(DefaultState.Type.CALLBACK); - - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer( - provider, TypeFactory.defaultInstance().constructType(CallbackState.class)) - .serialize(callbackState, gen, provider); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/ContinueAsSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/ContinueAsSerializer.java deleted file mode 100644 index d3b878cd..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/ContinueAsSerializer.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.end.ContinueAs; -import java.io.IOException; - -public class ContinueAsSerializer extends StdSerializer { - - public ContinueAsSerializer() { - this(ContinueAs.class); - } - - protected ContinueAsSerializer(Class t) { - super(t); - } - - @Override - public void serialize(ContinueAs continueAs, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - if (continueAs != null) { - if ((continueAs.getWorkflowId() != null && !continueAs.getWorkflowId().isEmpty()) - && (continueAs.getVersion() == null || continueAs.getVersion().isEmpty()) - && (continueAs.getData() == null || continueAs.getData().isEmpty()) - && continueAs.getWorkflowExecTimeout() == null) { - gen.writeString(continueAs.getWorkflowId()); - } else { - gen.writeStartObject(); - - if (continueAs.getWorkflowId() != null && continueAs.getWorkflowId().length() > 0) { - gen.writeStringField("workflowId", continueAs.getWorkflowId()); - } - - if (continueAs.getVersion() != null && continueAs.getVersion().length() > 0) { - gen.writeStringField("version", continueAs.getVersion()); - } - - if (continueAs.getData() != null && continueAs.getData().length() > 0) { - gen.writeStringField("data", continueAs.getData()); - } - - if (continueAs.getWorkflowExecTimeout() != null) { - gen.writeObjectField("workflowExecTimeout", continueAs.getWorkflowExecTimeout()); - } - - gen.writeEndObject(); - } - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/CronSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/CronSerializer.java deleted file mode 100644 index 7de22bd0..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/CronSerializer.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.cron.Cron; -import java.io.IOException; - -public class CronSerializer extends StdSerializer { - - public CronSerializer() { - this(Cron.class); - } - - protected CronSerializer(Class t) { - super(t); - } - - @Override - public void serialize(Cron cron, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - if (cron != null) { - if ((cron.getValidUntil() == null || cron.getValidUntil().isEmpty()) - && cron.getExpression() != null - && cron.getExpression().length() > 0) { - gen.writeString(cron.getExpression()); - } else { - gen.writeStartObject(); - - if (cron.getExpression() != null && cron.getExpression().length() > 0) { - gen.writeStringField("expression", cron.getExpression()); - } - - if (cron.getValidUntil() != null && cron.getValidUntil().length() > 0) { - gen.writeStringField("validUntil", cron.getValidUntil()); - } - - gen.writeEndObject(); - } - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/EndDefinitionSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/EndDefinitionSerializer.java deleted file mode 100644 index 743c50b0..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/EndDefinitionSerializer.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.end.End; -import io.serverlessworkflow.api.produce.ProduceEvent; -import java.io.IOException; - -public class EndDefinitionSerializer extends StdSerializer { - - public EndDefinitionSerializer() { - this(End.class); - } - - protected EndDefinitionSerializer(Class t) { - super(t); - } - - @Override - public void serialize(End end, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - if (end != null) { - if ((end.getProduceEvents() == null || end.getProduceEvents().size() < 1) - && end.getContinueAs() == null - && !end.isCompensate() - && !end.isTerminate()) { - gen.writeBoolean(true); - } else { - gen.writeStartObject(); - - if (end.isTerminate()) { - gen.writeBooleanField("terminate", true); - } - - if (end.getProduceEvents() != null && !end.getProduceEvents().isEmpty()) { - gen.writeArrayFieldStart("produceEvents"); - for (ProduceEvent produceEvent : end.getProduceEvents()) { - gen.writeObject(produceEvent); - } - gen.writeEndArray(); - } - - if (end.isCompensate()) { - gen.writeBooleanField("compensate", true); - } - - if (end.getContinueAs() != null) { - gen.writeObjectField("continueAs", end.getContinueAs()); - } - - gen.writeEndObject(); - } - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/EventDefinitionSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/EventDefinitionSerializer.java deleted file mode 100644 index d9faa8e2..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/EventDefinitionSerializer.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.events.EventDefinition; -import java.io.IOException; - -public class EventDefinitionSerializer extends StdSerializer { - - public EventDefinitionSerializer() { - this(EventDefinition.class); - } - - protected EventDefinitionSerializer(Class t) { - super(t); - } - - @Override - public void serialize( - EventDefinition triggerEvent, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer( - provider, TypeFactory.defaultInstance().constructType(EventDefinition.class)) - .serialize(triggerEvent, gen, provider); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/EventStateSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/EventStateSerializer.java deleted file mode 100644 index f7aacd8c..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/EventStateSerializer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.api.states.EventState; -import java.io.IOException; - -public class EventStateSerializer extends StdSerializer { - - public EventStateSerializer() { - this(EventState.class); - } - - protected EventStateSerializer(Class t) { - super(t); - } - - @Override - public void serialize(EventState eventState, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - // set defaults for end state - eventState.setType(DefaultState.Type.EVENT); - - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer(provider, TypeFactory.defaultInstance().constructType(EventState.class)) - .serialize(eventState, gen, provider); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/ExtensionSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/ExtensionSerializer.java deleted file mode 100644 index 9748a561..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/ExtensionSerializer.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.interfaces.Extension; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class ExtensionSerializer extends StdSerializer { - - private Map> extensionsMap = new HashMap<>(); - - public ExtensionSerializer() { - this(Extension.class); - } - - protected ExtensionSerializer(Class t) { - super(t); - } - - public void addExtension(String extensionId, Class extensionClass) { - this.extensionsMap.put(extensionId, extensionClass); - } - - @Override - public void serialize(Extension extension, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - String extensionId = extension.getExtensionId(); - - if (extensionsMap.containsKey(extensionId)) { - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer( - provider, TypeFactory.defaultInstance().constructType(extensionsMap.get(extensionId))) - .serialize(extension, gen, provider); - } else { - throw new IllegalArgumentException("Extension handler not registered for: " + extensionId); - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/ForEachStateSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/ForEachStateSerializer.java deleted file mode 100644 index 8b6aee9d..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/ForEachStateSerializer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.api.states.ForEachState; -import java.io.IOException; - -public class ForEachStateSerializer extends StdSerializer { - - public ForEachStateSerializer() { - this(ForEachState.class); - } - - protected ForEachStateSerializer(Class t) { - super(t); - } - - @Override - public void serialize(ForEachState forEachState, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - // set defaults for foreach state - forEachState.setType(DefaultState.Type.FOREACH); - - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer(provider, TypeFactory.defaultInstance().constructType(ForEachState.class)) - .serialize(forEachState, gen, provider); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/FunctionRefSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/FunctionRefSerializer.java deleted file mode 100644 index cf5ce81f..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/FunctionRefSerializer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.functions.FunctionRef; -import java.io.IOException; - -public class FunctionRefSerializer extends StdSerializer { - - public FunctionRefSerializer() { - this(FunctionRef.class); - } - - protected FunctionRefSerializer(Class t) { - super(t); - } - - @Override - public void serialize(FunctionRef functionRef, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - if (functionRef != null) { - if ((functionRef.getArguments() == null || functionRef.getArguments().isEmpty()) - && (functionRef.getSelectionSet() == null || functionRef.getSelectionSet().isEmpty()) - && (functionRef.getInvoke() == null - || functionRef.getInvoke().equals(FunctionRef.Invoke.SYNC)) - && functionRef.getRefName() != null - && functionRef.getRefName().length() > 0) { - gen.writeString(functionRef.getRefName()); - } else { - gen.writeStartObject(); - - if (functionRef.getRefName() != null && functionRef.getRefName().length() > 0) { - gen.writeStringField("refName", functionRef.getRefName()); - } - - if (functionRef.getArguments() != null && !functionRef.getArguments().isEmpty()) { - gen.writeObjectField("arguments", functionRef.getArguments()); - } - - if (functionRef.getSelectionSet() != null && functionRef.getSelectionSet().length() > 0) { - gen.writeStringField("selectionSet", functionRef.getSelectionSet()); - } - - if (functionRef.getInvoke() != null) { - gen.writeStringField("invoke", functionRef.getInvoke().value()); - } - - gen.writeEndObject(); - } - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/InjectStateSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/InjectStateSerializer.java deleted file mode 100644 index 06f488bf..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/InjectStateSerializer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.api.states.InjectState; -import java.io.IOException; - -public class InjectStateSerializer extends StdSerializer { - - public InjectStateSerializer() { - this(InjectState.class); - } - - protected InjectStateSerializer(Class t) { - super(t); - } - - @Override - public void serialize(InjectState relayState, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - // set defaults for relay state - relayState.setType(DefaultState.Type.INJECT); - - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer(provider, TypeFactory.defaultInstance().constructType(InjectState.class)) - .serialize(relayState, gen, provider); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/OperationStateSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/OperationStateSerializer.java deleted file mode 100644 index a5389a07..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/OperationStateSerializer.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.api.states.OperationState; -import java.io.IOException; - -public class OperationStateSerializer extends StdSerializer { - - public OperationStateSerializer() { - this(OperationState.class); - } - - protected OperationStateSerializer(Class t) { - super(t); - } - - @Override - public void serialize( - OperationState operationState, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - // set defaults for delay state - operationState.setType(DefaultState.Type.OPERATION); - - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer( - provider, TypeFactory.defaultInstance().constructType(OperationState.class)) - .serialize(operationState, gen, provider); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/ParallelStateSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/ParallelStateSerializer.java deleted file mode 100644 index 115ffd00..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/ParallelStateSerializer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.api.states.ParallelState; -import java.io.IOException; - -public class ParallelStateSerializer extends StdSerializer { - - public ParallelStateSerializer() { - this(ParallelState.class); - } - - protected ParallelStateSerializer(Class t) { - super(t); - } - - @Override - public void serialize(ParallelState parallelState, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - // set defaults for end state - parallelState.setType(DefaultState.Type.PARALLEL); - - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer( - provider, TypeFactory.defaultInstance().constructType(ParallelState.class)) - .serialize(parallelState, gen, provider); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/ScheduleSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/ScheduleSerializer.java deleted file mode 100644 index 9f3d6f74..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/ScheduleSerializer.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.schedule.Schedule; -import java.io.IOException; - -public class ScheduleSerializer extends StdSerializer { - - public ScheduleSerializer() { - this(Schedule.class); - } - - protected ScheduleSerializer(Class t) { - super(t); - } - - @Override - public void serialize(Schedule schedule, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - if (schedule != null) { - if (schedule.getCron() == null - && (schedule.getTimezone() == null || schedule.getTimezone().isEmpty()) - && schedule.getInterval() != null - && schedule.getInterval().length() > 0) { - gen.writeString(schedule.getInterval()); - } else { - gen.writeStartObject(); - - if (schedule.getInterval() != null && schedule.getInterval().length() > 0) { - gen.writeStringField("interval", schedule.getInterval()); - } - - if (schedule.getCron() != null) { - gen.writeObjectField("cron", schedule.getCron()); - } - - if (schedule.getTimezone() != null && schedule.getTimezone().length() > 0) { - gen.writeStringField("timezone", schedule.getTimezone()); - } - - gen.writeEndObject(); - } - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/SleepStateSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/SleepStateSerializer.java deleted file mode 100644 index 8ba529a6..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/SleepStateSerializer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.api.states.SleepState; -import java.io.IOException; - -public class SleepStateSerializer extends StdSerializer { - - public SleepStateSerializer() { - this(SleepState.class); - } - - protected SleepStateSerializer(Class t) { - super(t); - } - - @Override - public void serialize(SleepState delayState, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - // set defaults for delay state - delayState.setType(DefaultState.Type.SLEEP); - - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer(provider, TypeFactory.defaultInstance().constructType(SleepState.class)) - .serialize(delayState, gen, provider); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/StartDefinitionSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/StartDefinitionSerializer.java deleted file mode 100644 index 8f1142f1..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/StartDefinitionSerializer.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.start.Start; -import java.io.IOException; - -public class StartDefinitionSerializer extends StdSerializer { - - public StartDefinitionSerializer() { - this(Start.class); - } - - protected StartDefinitionSerializer(Class t) { - super(t); - } - - @Override - public void serialize(Start start, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - if (start != null) { - if (start.getStateName() != null - && start.getStateName().length() > 0 - && start.getSchedule() == null) { - gen.writeString(start.getStateName()); - } else { - gen.writeStartObject(); - - if (start.getStateName() != null && start.getStateName().length() > 0) { - gen.writeStringField("stateName", start.getStateName()); - } - - if (start.getSchedule() != null) { - gen.writeObjectField("schedule", start.getSchedule()); - } - - gen.writeEndObject(); - } - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/StateExecTimeoutSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/StateExecTimeoutSerializer.java deleted file mode 100644 index f28b57da..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/StateExecTimeoutSerializer.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.timeouts.StateExecTimeout; -import java.io.IOException; - -public class StateExecTimeoutSerializer extends StdSerializer { - - public StateExecTimeoutSerializer() { - this(StateExecTimeout.class); - } - - protected StateExecTimeoutSerializer(Class t) { - super(t); - } - - @Override - public void serialize( - StateExecTimeout stateExecTimeout, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - if (stateExecTimeout != null) { - if ((stateExecTimeout.getTotal() != null && !stateExecTimeout.getTotal().isEmpty()) - && (stateExecTimeout.getSingle() == null || stateExecTimeout.getSingle().isEmpty())) { - gen.writeString(stateExecTimeout.getTotal()); - } else { - gen.writeStartObject(); - - if (stateExecTimeout.getTotal() != null && stateExecTimeout.getTotal().length() > 0) { - gen.writeStringField("total", stateExecTimeout.getTotal()); - } - - if (stateExecTimeout.getSingle() != null && stateExecTimeout.getSingle().length() > 0) { - gen.writeStringField("single", stateExecTimeout.getSingle()); - } - - gen.writeEndObject(); - } - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/SubFlowRefSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/SubFlowRefSerializer.java deleted file mode 100644 index 4b94b9e4..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/SubFlowRefSerializer.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.functions.SubFlowRef; -import java.io.IOException; - -public class SubFlowRefSerializer extends StdSerializer { - - public SubFlowRefSerializer() { - this(SubFlowRef.class); - } - - protected SubFlowRefSerializer(Class t) { - super(t); - } - - @Override - public void serialize(SubFlowRef subflowRef, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - if (subflowRef != null) { - if ((subflowRef.getWorkflowId() == null || subflowRef.getWorkflowId().isEmpty()) - && (subflowRef.getVersion() == null || subflowRef.getVersion().isEmpty()) - && (subflowRef.getInvoke() == null - || subflowRef.getInvoke().equals(SubFlowRef.Invoke.SYNC))) { - gen.writeString(subflowRef.getWorkflowId()); - } else { - gen.writeStartObject(); - - if (subflowRef.getWorkflowId() != null && subflowRef.getWorkflowId().length() > 0) { - gen.writeStringField("workflowId", subflowRef.getWorkflowId()); - } - - if (subflowRef.getVersion() != null && subflowRef.getVersion().length() > 0) { - gen.writeStringField("version", subflowRef.getVersion()); - } - - if (subflowRef.getOnParentComplete() != null) { - gen.writeStringField("onParentComplete", subflowRef.getOnParentComplete().value()); - } - - if (subflowRef.getInvoke() != null) { - gen.writeStringField("invoke", subflowRef.getInvoke().value()); - } - - gen.writeEndObject(); - } - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/SwitchStateSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/SwitchStateSerializer.java deleted file mode 100644 index d5a725d0..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/SwitchStateSerializer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import com.fasterxml.jackson.databind.type.TypeFactory; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.api.states.SwitchState; -import java.io.IOException; - -public class SwitchStateSerializer extends StdSerializer { - - public SwitchStateSerializer() { - this(SwitchState.class); - } - - protected SwitchStateSerializer(Class t) { - super(t); - } - - @Override - public void serialize(SwitchState switchState, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - // set defaults for end state - switchState.setType(DefaultState.Type.SWITCH); - - // serialize after setting default bean values... - BeanSerializerFactory.instance - .createSerializer(provider, TypeFactory.defaultInstance().constructType(SwitchState.class)) - .serialize(switchState, gen, provider); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/TransitionSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/TransitionSerializer.java deleted file mode 100644 index 12699ccc..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/TransitionSerializer.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.produce.ProduceEvent; -import io.serverlessworkflow.api.transitions.Transition; -import java.io.IOException; - -public class TransitionSerializer extends StdSerializer { - - public TransitionSerializer() { - this(Transition.class); - } - - protected TransitionSerializer(Class t) { - super(t); - } - - @Override - public void serialize(Transition transition, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - if (transition != null) { - if ((transition.getProduceEvents() == null || transition.getProduceEvents().size() < 1) - && !transition.isCompensate() - && transition.getNextState() != null - && transition.getNextState().length() > 0) { - gen.writeString(transition.getNextState()); - } else { - gen.writeStartObject(); - - if (transition.getProduceEvents() != null && !transition.getProduceEvents().isEmpty()) { - gen.writeArrayFieldStart("produceEvents"); - for (ProduceEvent produceEvent : transition.getProduceEvents()) { - gen.writeObject(produceEvent); - } - gen.writeEndArray(); - } - - if (transition.isCompensate()) { - gen.writeBooleanField("compensate", true); - } - - if (transition.getNextState() != null && transition.getNextState().length() > 0) { - gen.writeStringField("nextState", transition.getNextState()); - } - - gen.writeEndObject(); - } - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/serializers/WorkflowSerializer.java b/api/src/main/java/io/serverlessworkflow/api/serializers/WorkflowSerializer.java deleted file mode 100644 index beeba2fb..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/serializers/WorkflowSerializer.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.serializers; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.error.ErrorDefinition; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.interfaces.Extension; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.retry.RetryDefinition; -import java.io.IOException; -import java.security.MessageDigest; -import java.util.UUID; - -public class WorkflowSerializer extends StdSerializer { - - public WorkflowSerializer() { - this(Workflow.class); - } - - protected WorkflowSerializer(Class t) { - super(t); - } - - private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); - - @Override - public void serialize(Workflow workflow, JsonGenerator gen, SerializerProvider provider) - throws IOException { - - gen.writeStartObject(); - - if (workflow.getId() != null && !workflow.getId().isEmpty()) { - gen.writeStringField("id", workflow.getId()); - } else { - gen.writeStringField("id", generateUniqueId()); - } - - if (workflow.getKey() != null) { - gen.writeStringField("key", workflow.getKey()); - } - gen.writeStringField("name", workflow.getName()); - - if (workflow.getDescription() != null && !workflow.getDescription().isEmpty()) { - gen.writeStringField("description", workflow.getDescription()); - } - - if (workflow.getVersion() != null && !workflow.getVersion().isEmpty()) { - gen.writeStringField("version", workflow.getVersion()); - } - - if (workflow.getAnnotations() != null && !workflow.getAnnotations().isEmpty()) { - gen.writeObjectField("annotations", workflow.getAnnotations()); - } - - if (workflow.getDataInputSchema() != null) { - if (workflow.getDataInputSchema().getRefValue() != null - && workflow.getDataInputSchema().getRefValue().length() > 0 - && workflow.getDataInputSchema().isFailOnValidationErrors()) { - gen.writeStringField("dataInputSchema", workflow.getDataInputSchema().getRefValue()); - - } else if (workflow.getDataInputSchema().getSchemaDef() != null - && !workflow.getDataInputSchema().getSchemaDef().isEmpty() - && !workflow.getDataInputSchema().isFailOnValidationErrors()) { - gen.writeObjectField("dataInputSchema", workflow.getDataInputSchema().getSchemaDef()); - } - } - - if (workflow.getStart() != null) { - gen.writeObjectField("start", workflow.getStart()); - } - - if (workflow.getSpecVersion() != null && !workflow.getSpecVersion().isEmpty()) { - gen.writeStringField("specVersion", workflow.getSpecVersion()); - } - - if (workflow.getExtensions() != null && !workflow.getExpressionLang().isEmpty()) { - gen.writeStringField("expressionLang", workflow.getExpressionLang()); - } - - if (workflow.isKeepActive()) { - gen.writeBooleanField("keepActive", workflow.isKeepActive()); - } - - if (workflow.isAutoRetries()) { - gen.writeBooleanField("autoRetries", workflow.isAutoRetries()); - } - - if (workflow.getMetadata() != null && !workflow.getMetadata().isEmpty()) { - gen.writeObjectField("metadata", workflow.getMetadata()); - } - - if (workflow.getEvents() != null && !workflow.getEvents().getEventDefs().isEmpty()) { - gen.writeArrayFieldStart("events"); - for (EventDefinition eventDefinition : workflow.getEvents().getEventDefs()) { - gen.writeObject(eventDefinition); - } - gen.writeEndArray(); - } - - if (workflow.getFunctions() != null && !workflow.getFunctions().getFunctionDefs().isEmpty()) { - gen.writeArrayFieldStart("functions"); - for (FunctionDefinition function : workflow.getFunctions().getFunctionDefs()) { - gen.writeObject(function); - } - gen.writeEndArray(); - } - - if (workflow.getRetries() != null && !workflow.getRetries().getRetryDefs().isEmpty()) { - gen.writeArrayFieldStart("retries"); - for (RetryDefinition retry : workflow.getRetries().getRetryDefs()) { - gen.writeObject(retry); - } - gen.writeEndArray(); - } - - if (workflow.getErrors() != null && !workflow.getErrors().getErrorDefs().isEmpty()) { - gen.writeArrayFieldStart("errors"); - for (ErrorDefinition error : workflow.getErrors().getErrorDefs()) { - gen.writeObject(error); - } - gen.writeEndArray(); - } - - if (workflow.getSecrets() != null && !workflow.getSecrets().getSecretDefs().isEmpty()) { - gen.writeArrayFieldStart("secrets"); - for (String secretDef : workflow.getSecrets().getSecretDefs()) { - gen.writeString(secretDef); - } - gen.writeEndArray(); - } - - if (workflow.getConstants() != null) { - if (workflow.getConstants().getConstantsDef() != null - && !workflow.getConstants().getConstantsDef().isEmpty()) { - gen.writeObjectField("constants", workflow.getConstants().getConstantsDef()); - } else if (workflow.getConstants().getRefValue() != null) { - gen.writeStringField("constants", workflow.getConstants().getRefValue()); - } - } - - if (workflow.getTimeouts() != null) { - gen.writeObjectField("timeouts", workflow.getTimeouts()); - } - - if (workflow.getAuth() != null && !workflow.getAuth().getAuthDefs().isEmpty()) { - gen.writeObjectField("auth", workflow.getAuth().getAuthDefs()); - } - - if (workflow.getStates() != null && !workflow.getStates().isEmpty()) { - gen.writeArrayFieldStart("states"); - for (State state : workflow.getStates()) { - gen.writeObject(state); - } - gen.writeEndArray(); - } - - if (workflow.getExtensions() != null && !workflow.getExtensions().isEmpty()) { - gen.writeArrayFieldStart("extensions"); - for (Extension extension : workflow.getExtensions()) { - gen.writeObject(extension); - } - gen.writeEndArray(); - } - - gen.writeEndObject(); - } - - protected static String generateUniqueId() { - try { - MessageDigest salt = MessageDigest.getInstance("SHA-256"); - - salt.update(UUID.randomUUID().toString().getBytes("UTF-8")); - return bytesToHex(salt.digest()); - } catch (Exception e) { - return UUID.randomUUID().toString(); - } - } - - protected static String bytesToHex(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java b/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java deleted file mode 100644 index 9bdce416..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.utils; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.serverlessworkflow.api.mapper.JsonObjectMapperFactory; -import io.serverlessworkflow.api.mapper.YamlObjectMapperFactory; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.stream.Collectors; - -public class Utils { - - @SuppressWarnings("DefaultCharset") - public static String getResourceFileAsString(String fileName) throws IOException { - ClassLoader classLoader = ClassLoader.getSystemClassLoader(); - try (InputStream is = classLoader.getResourceAsStream(fileName)) { - if (is == null) return null; - try (InputStreamReader isr = new InputStreamReader(is); - BufferedReader reader = new BufferedReader(isr)) { - return reader.lines().collect(Collectors.joining(System.lineSeparator())); - } - } - } - - public static ObjectMapper getObjectMapper(String source) { - return !source.trim().startsWith("{") - ? YamlObjectMapperFactory.mapper() - : JsonObjectMapperFactory.mapper(); - } - - public static JsonNode getNode(String source) throws JsonProcessingException { - return getObjectMapper(source).readTree(source); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/validation/ValidationError.java b/api/src/main/java/io/serverlessworkflow/api/validation/ValidationError.java deleted file mode 100644 index edb92eff..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/validation/ValidationError.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.validation; - -public class ValidationError { - private static final String MSG_FORMAT = "%s:%s"; - public static final String SCHEMA_VALIDATION = "schemavalidation"; - public static final String WORKFLOW_VALIDATION = "workflowvalidation"; - - private String message; - private String type; - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - @Override - public String toString() { - return String.format(MSG_FORMAT, type, message); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java b/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java deleted file mode 100644 index 847380fb..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.validation; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.IOException; -import java.io.UncheckedIOException; - -public class WorkflowSchemaLoader { - - public static JsonNode getWorkflowSchema() { - try { - return ObjectMapperHolder.objectMapper.readTree( - WorkflowSchemaLoader.class.getResourceAsStream("/schema/workflow.json")); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private static class ObjectMapperHolder { - public static final ObjectMapper objectMapper = new ObjectMapper(); - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/workflow/Auth.java b/api/src/main/java/io/serverlessworkflow/api/workflow/Auth.java deleted file mode 100644 index 53fa2922..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/workflow/Auth.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2022-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.serverlessworkflow.api.workflow; - -import io.serverlessworkflow.api.auth.AuthDefinition; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -public class Auth implements Serializable { - private String refValue; - private List authDefs; - - public Auth() {} - - public Auth(AuthDefinition authDef) { - this.authDefs = new ArrayList<>(); - this.authDefs.add(authDef); - } - - public Auth(List authDefs) { - this.authDefs = authDefs; - } - - public Auth(String refValue) { - this.refValue = refValue; - } - - public String getRefValue() { - return refValue; - } - - public void setRefValue(String refValue) { - this.refValue = refValue; - } - - public List getAuthDefs() { - return authDefs; - } - - public void setAuthDefs(List authDefs) { - this.authDefs = authDefs; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/workflow/BaseWorkflow.java b/api/src/main/java/io/serverlessworkflow/api/workflow/BaseWorkflow.java deleted file mode 100644 index 61692caf..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/workflow/BaseWorkflow.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.workflow; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.mapper.JsonObjectMapper; -import io.serverlessworkflow.api.mapper.YamlObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** Base Workflow provides some extra functionality for the Workflow types */ -public class BaseWorkflow { - - private static JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(); - private static YamlObjectMapper yamlObjectMapper = new YamlObjectMapper(); - - private static Logger logger = LoggerFactory.getLogger(BaseWorkflow.class); - - public static Workflow fromSource(String source) { - // try it as json markup first, if fails try yaml - try { - return jsonObjectMapper.readValue(source, Workflow.class); - } catch (Exception e) { - logger.info("Unable to convert as json markup, trying as yaml"); - try { - return yamlObjectMapper.readValue(source, Workflow.class); - } catch (Exception ee) { - throw new IllegalArgumentException( - "Could not convert markup to Workflow: " + ee.getMessage()); - } - } - } - - public static String toJson(Workflow workflow) { - try { - return jsonObjectMapper.writeValueAsString(workflow); - } catch (JsonProcessingException e) { - logger.error("Error mapping to json: " + e.getMessage()); - return null; - } - } - - public static String toYaml(Workflow workflow) { - try { - String jsonString = jsonObjectMapper.writeValueAsString(workflow); - JsonNode jsonNode = jsonObjectMapper.readTree(jsonString); - YAMLFactory yamlFactory = - new YAMLFactory() - .disable(YAMLGenerator.Feature.MINIMIZE_QUOTES) - .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); - return new YAMLMapper(yamlFactory).writeValueAsString(jsonNode); - } catch (Exception e) { - logger.error("Error mapping to yaml: " + e.getMessage()); - return null; - } - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/workflow/Constants.java b/api/src/main/java/io/serverlessworkflow/api/workflow/Constants.java deleted file mode 100644 index 3afbddc2..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/workflow/Constants.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.workflow; - -import com.fasterxml.jackson.databind.JsonNode; -import java.io.Serializable; - -public class Constants implements Serializable { - private String refValue; - private JsonNode constantsDef; - - public Constants() {} - - public Constants(String refValue) { - this.refValue = refValue; - } - - public Constants(JsonNode constantsDef) { - this.constantsDef = constantsDef; - } - - public String getRefValue() { - return refValue; - } - - public void setRefValue(String refValue) { - this.refValue = refValue; - } - - public JsonNode getConstantsDef() { - return constantsDef; - } - - public void setConstantsDef(JsonNode constantsDef) { - this.constantsDef = constantsDef; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/workflow/DataInputSchema.java b/api/src/main/java/io/serverlessworkflow/api/workflow/DataInputSchema.java deleted file mode 100644 index ba0dd333..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/workflow/DataInputSchema.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.workflow; - -import com.fasterxml.jackson.databind.JsonNode; -import java.io.Serializable; - -public class DataInputSchema implements Serializable { - private String refValue; - private JsonNode schemaDef; - private boolean failOnValidationErrors = true; - - public DataInputSchema() {} - - public DataInputSchema(String refValue) { - this.refValue = refValue; - } - - public String getRefValue() { - return refValue; - } - - public void setRefValue(String refValue) { - this.refValue = refValue; - } - - public JsonNode getSchemaDef() { - return schemaDef; - } - - public void setSchemaDef(JsonNode schemaDef) { - this.schemaDef = schemaDef; - } - - public boolean isFailOnValidationErrors() { - return failOnValidationErrors; - } - - public void setFailOnValidationErrors(boolean failOnValidationErrors) { - this.failOnValidationErrors = failOnValidationErrors; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/workflow/Errors.java b/api/src/main/java/io/serverlessworkflow/api/workflow/Errors.java deleted file mode 100644 index c6418863..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/workflow/Errors.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.workflow; - -import io.serverlessworkflow.api.error.ErrorDefinition; -import java.io.Serializable; -import java.util.List; - -public class Errors implements Serializable { - private String refValue; - private List errorDefs; - - public Errors() {} - - public Errors(List errorDefs) { - this.errorDefs = errorDefs; - } - - public Errors(String refValue) { - this.refValue = refValue; - } - - public String getRefValue() { - return refValue; - } - - public void setRefValue(String refValue) { - this.refValue = refValue; - } - - public List getErrorDefs() { - return errorDefs; - } - - public void setErrorDefs(List errorDefs) { - this.errorDefs = errorDefs; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/workflow/Events.java b/api/src/main/java/io/serverlessworkflow/api/workflow/Events.java deleted file mode 100644 index a90c7d6a..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/workflow/Events.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.workflow; - -import io.serverlessworkflow.api.events.EventDefinition; -import java.io.Serializable; -import java.util.List; - -public class Events implements Serializable { - private String refValue; - private List eventDefs; - - public Events() {} - - public Events(List eventDefs) { - this.eventDefs = eventDefs; - } - - public Events(String refValue) { - this.refValue = refValue; - } - - public String getRefValue() { - return refValue; - } - - public void setRefValue(String refValue) { - this.refValue = refValue; - } - - public List getEventDefs() { - return eventDefs; - } - - public void setEventDefs(List eventDefs) { - this.eventDefs = eventDefs; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/workflow/Functions.java b/api/src/main/java/io/serverlessworkflow/api/workflow/Functions.java deleted file mode 100644 index 1c01c35e..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/workflow/Functions.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.workflow; - -import io.serverlessworkflow.api.functions.FunctionDefinition; -import java.io.Serializable; -import java.util.List; - -public class Functions implements Serializable { - private String refValue; - private List functionDefs; - - public Functions() {} - - public Functions(List functionDefs) { - this.functionDefs = functionDefs; - } - - public Functions(String refValue) { - this.refValue = refValue; - } - - public String getRefValue() { - return refValue; - } - - public void setRefValue(String refValue) { - this.refValue = refValue; - } - - public List getFunctionDefs() { - return functionDefs; - } - - public void setFunctionDefs(List functionDefs) { - this.functionDefs = functionDefs; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/workflow/Retries.java b/api/src/main/java/io/serverlessworkflow/api/workflow/Retries.java deleted file mode 100644 index be79f9ab..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/workflow/Retries.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.workflow; - -import io.serverlessworkflow.api.retry.RetryDefinition; -import java.io.Serializable; -import java.util.List; - -public class Retries implements Serializable { - private String refValue; - private List retryDefs; - - public Retries() {} - - public Retries(List retryDefs) { - this.retryDefs = retryDefs; - } - - public Retries(String refValue) { - this.refValue = refValue; - } - - public String getRefValue() { - return refValue; - } - - public void setRefValue(String refValue) { - this.refValue = refValue; - } - - public List getRetryDefs() { - return retryDefs; - } - - public void setRetryDefs(List retryDefs) { - this.retryDefs = retryDefs; - } -} diff --git a/api/src/main/java/io/serverlessworkflow/api/workflow/Secrets.java b/api/src/main/java/io/serverlessworkflow/api/workflow/Secrets.java deleted file mode 100644 index 0783b196..00000000 --- a/api/src/main/java/io/serverlessworkflow/api/workflow/Secrets.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.workflow; - -import java.io.Serializable; -import java.util.List; - -public class Secrets implements Serializable { - private String refValue; - private List secretDefs; - - public Secrets() {} - - public Secrets(String refValue) { - this.refValue = refValue; - } - - public Secrets(List secretDefs) { - this.secretDefs = secretDefs; - } - - public String getRefValue() { - return refValue; - } - - public void setRefValue(String refValue) { - this.refValue = refValue; - } - - public List getSecretDefs() { - return secretDefs; - } - - public void setSecretDefs(List secretDefs) { - this.secretDefs = secretDefs; - } -} diff --git a/api/src/main/resources/schema/actions/action.json b/api/src/main/resources/schema/actions/action.json deleted file mode 100644 index 54354029..00000000 --- a/api/src/main/resources/schema/actions/action.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.actions.Action", - "description": "Action Definition", - "properties": { - "id": { - "type": "string", - "description": "Unique action identifier" - }, - "name": { - "type": "string", - "description": "Unique action definition name" - }, - "functionRef": { - "description": "References a reusable function definition to be invoked", - "$ref": "../functions/functionref.json" - }, - "eventRef": { - "description": "References a 'trigger' and 'result' reusable event definitions", - "$ref": "../events/eventref.json" - }, - "subFlowRef": { - "description": "References a sub-workflow to invoke", - "$ref": "../functions/subflowref.json" - }, - "sleep": { - "$ref": "../sleep/sleep.json" - }, - "retryRef": { - "type": "string", - "description": "References a defined workflow retry definition. If not defined the default retry policy is assumed" - }, - "nonRetryableErrors": { - "type": "array", - "description": "List of unique references to defined workflow errors for which the action should not be retried. Used only when `autoRetries` is set to `true`", - "minItems": 1, - "items": { - "type": "string" - } - }, - "retryableErrors": { - "type": "array", - "description": "List of unique references to defined workflow errors for which the action should be retried. Used only when `autoRetries` is set to `false`", - "minItems": 1, - "items": { - "type": "string" - } - }, - "actionDataFilter": { - "$ref": "../filters/actiondatafilter.json" - }, - "condition": { - "description": "Expression, if defined, must evaluate to true for this action to be performed. If false, action is disregarded", - "type": "string", - "minLength": 1 - } - }, - "oneOf": [ - { - "required": [ - "functionRef" - ] - }, - { - "required": [ - "eventRef" - ] - }, - { - "required": [ - "subFlowRef" - ] - } - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/auth/auth.json b/api/src/main/resources/schema/auth/auth.json deleted file mode 100644 index c8ece5ee..00000000 --- a/api/src/main/resources/schema/auth/auth.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.auth.AuthDefinition", - "description": "Auth Definition", - "properties": { - "name": { - "type": "string", - "description": "Unique auth definition name", - "minLength": 1 - }, - "scheme": { - "type": "string", - "description": "Defines the auth type", - "enum": [ - "basic", - "bearer", - "oauth2" - ], - "default": "basic" - }, - "basicauth": { - "$ref": "basicauthdef.json" - }, - "bearerauth": { - "$ref": "bearerauthdef.json" - }, - "oauth": { - "$ref": "oauthdef.json" - } - }, - "required": [ - - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/auth/basicauthdef.json b/api/src/main/resources/schema/auth/basicauthdef.json deleted file mode 100644 index f7c80da1..00000000 --- a/api/src/main/resources/schema/auth/basicauthdef.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.auth.BasicAuthDefinition", - "properties": { - "username": { - "type": "string", - "description": "String or a workflow expression. Contains the user name", - "minLength": 1 - }, - "password": { - "type": "string", - "description": "String or a workflow expression. Contains the user password", - "minLength": 1 - }, - "metadata": { - "$ref": "../metadata/metadata.json" - } - }, - "required": [ - "username", - "password" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/auth/bearerauthdef.json b/api/src/main/resources/schema/auth/bearerauthdef.json deleted file mode 100644 index 61dfd137..00000000 --- a/api/src/main/resources/schema/auth/bearerauthdef.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.auth.BearerAuthDefinition", - "properties": { - "token": { - "type": "string", - "description": "String or a workflow expression. Contains the token", - "minLength": 1 - }, - "metadata": { - "$ref": "../metadata/metadata.json" - } - }, - "required": [ - "token" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/auth/oauthdef.json b/api/src/main/resources/schema/auth/oauthdef.json deleted file mode 100644 index 4354be2c..00000000 --- a/api/src/main/resources/schema/auth/oauthdef.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.auth.OauthDefinition", - "properties": { - "authority": { - "type": "string", - "description": "String or a workflow expression. Contains the authority information", - "minLength": 1 - }, - "grantType": { - "type": "string", - "description": "Defines the grant type", - "enum": [ - "password", - "clientCredentials", - "tokenExchange" - ], - "additionalItems": false - }, - "clientId": { - "type": "string", - "description": "String or a workflow expression. Contains the client identifier", - "minLength": 1 - }, - "clientSecret": { - "type": "string", - "description": "Workflow secret or a workflow expression. Contains the client secret", - "minLength": 1 - }, - "scopes": { - "type": "array", - "description": "Array containing strings or workflow expressions. Contains the OAuth2 scopes", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "username": { - "type": "string", - "description": "String or a workflow expression. Contains the user name. Used only if grantType is 'resourceOwner'", - "minLength": 1 - }, - "password": { - "type": "string", - "description": "String or a workflow expression. Contains the user password. Used only if grantType is 'resourceOwner'", - "minLength": 1 - }, - "audiences": { - "type": "array", - "description": "Array containing strings or workflow expressions. Contains the OAuth2 audiences", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "subjectToken": { - "type": "string", - "description": "String or a workflow expression. Contains the subject token", - "minLength": 1 - }, - "requestedSubject": { - "type": "string", - "description": "String or a workflow expression. Contains the requested subject", - "minLength": 1 - }, - "requestedIssuer": { - "type": "string", - "description": "String or a workflow expression. Contains the requested issuer", - "minLength": 1 - }, - "metadata": { - "$ref": "../metadata/metadata.json" - } - }, - "required": [ - "grantType", - "clientId" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/branches/branch.json b/api/src/main/resources/schema/branches/branch.json deleted file mode 100644 index cdfdb6d0..00000000 --- a/api/src/main/resources/schema/branches/branch.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.branches.Branch", - "description": "Branch Definition", - "properties": { - "name": { - "type": "string", - "description": "Branch name" - }, - "actions": { - "type": "array", - "description": "Actions to be executed in this branch", - "items": { - "type": "object", - "$ref": "../actions/action.json" - } - }, - "timeouts": { - "$ref": "../timeouts/timeoutsdef.json" - } - }, - "oneOf": [ - { - "required": [ - "name", - "actions" - ] - }, - { - "required": [ - "name" - ] - } - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/correlation/correlationdef.json b/api/src/main/resources/schema/correlation/correlationdef.json deleted file mode 100644 index 7f271b08..00000000 --- a/api/src/main/resources/schema/correlation/correlationdef.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.correlation.CorrelationDef", - "description": "CloudEvent correlation definition", - "properties": { - "contextAttributeName": { - "type": "string", - "description": "CloudEvent Extension Context Attribute name", - "minLength": 1 - }, - "contextAttributeValue": { - "type": "string", - "description": "CloudEvent Extension Context Attribute value", - "minLength": 1 - } - }, - "required": [ - "contextAttributeName" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/cron/crondef.json b/api/src/main/resources/schema/cron/crondef.json deleted file mode 100644 index 67bb43c5..00000000 --- a/api/src/main/resources/schema/cron/crondef.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.cron.Cron", - "description": "Schedule cron definition", - "properties": { - "expression": { - "type": "string", - "description": "Repeating interval (cron expression) describing when the workflow instance should be created" - }, - "validUntil": { - "type": "string", - "description": "Specific date and time (ISO 8601 format) when the cron expression invocation is no longer valid" - } - }, - "required": [ - "expression" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/defaultcondition/defaultconditiondef.json b/api/src/main/resources/schema/defaultcondition/defaultconditiondef.json deleted file mode 100644 index 862e5c4c..00000000 --- a/api/src/main/resources/schema/defaultcondition/defaultconditiondef.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.defaultdef.DefaultConditionDefinition", - "description": "Switch state default condition definition", - "properties": { - "transition": { - "$ref": "../transitions/transition.json", - "description": "Next transition of the workflow if there is valid matches" - }, - "end": { - "$ref": "../end/end.json", - "description": "Workflow end definition" - } - }, - "oneOf": [ - { - "required": [ - "transition" - ] - }, - { - "required": [ - "end" - ] - } - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/end/continueas.json b/api/src/main/resources/schema/end/continueas.json deleted file mode 100644 index 94c10e86..00000000 --- a/api/src/main/resources/schema/end/continueas.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.end.ContinueAs", - "description": "End definition continue as", - "properties": { - "workflowId": { - "type": "string", - "description": "Unique id of the workflow to continue execution as" - }, - "version": { - "type": "string", - "description": "Version of the workflow to continue execution as", - "minLength": 1 - }, - "data": { - "type": [ - "string" - ], - "description": "Expression which selects parts of the states data output to become the workflow data input of continued execution" - }, - "workflowExecTimeout": { - "$ref": "../timeouts/workflowexectimeout.json" - } - }, - "required": [ - "kind" - ] -}s \ No newline at end of file diff --git a/api/src/main/resources/schema/end/end.json b/api/src/main/resources/schema/end/end.json deleted file mode 100644 index 755ca929..00000000 --- a/api/src/main/resources/schema/end/end.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.end.End", - "description": "State end definition", - "properties": { - "terminate": { - "type": "boolean", - "default": false, - "description": "If true, completes all execution flows in the given workflow instance" - }, - "produceEvents": { - "type": "array", - "description": "Array of events to be produced", - "items": { - "type": "object", - "$ref": "../produce/produceevent.json" - } - }, - "compensate": { - "type": "boolean", - "default": false, - "description": "If set to true, triggers workflow compensation when before workflow executin completes. Default is false" - }, - "continueAs": { - "$ref": "continueas.json" - } - }, - "required": [ - "kind" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/error/error.json b/api/src/main/resources/schema/error/error.json deleted file mode 100644 index c51860de..00000000 --- a/api/src/main/resources/schema/error/error.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.error.Error", - "properties": { - "errorRef": { - "type": "string", - "description": "Reference to a unique workflow error definition. Used of errorRefs is not used", - "minLength": 1 - }, - "errorRefs": { - "type": "array", - "description": "References one or more workflow error definitions. Used if errorRef is not used", - "minItems": 1, - "items": { - "type": "string" - } - }, - "transition": { - "$ref": "../transitions/transition.json", - "description": "Transition to next state to handle the error. If retryRef is defined, this transition is taken only if retries were unsuccessful." - }, - "end": { - "description": "End workflow execution in case of this error. If retryRef is defined, this ends workflow only if retries were unsuccessful.", - "$ref": "../end/end.json" - } - }, - "required": [ - "error", - "transition" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/error/errordef.json b/api/src/main/resources/schema/error/errordef.json deleted file mode 100644 index 613d3cbf..00000000 --- a/api/src/main/resources/schema/error/errordef.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.error.ErrorDefinition", - "properties": { - "name": { - "type": "string", - "description": "Domain-specific error name", - "minLength": 1 - }, - "code": { - "type": "string", - "description": "Error code. Can be used in addition to the name to help runtimes resolve to technical errors/exceptions. Should not be defined if error is set to '*'", - "minLength": 1 - }, - "description": { - "type": "string", - "description": "Error description" - } - }, - "required": [ - "name" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/events/eventdef.json b/api/src/main/resources/schema/events/eventdef.json deleted file mode 100644 index a585f782..00000000 --- a/api/src/main/resources/schema/events/eventdef.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.events.EventDefinition", - "properties": { - "name": { - "type": "string", - "description": "Event Definition unique name", - "minLength": 1 - }, - "source": { - "type": "string", - "description": "CloudEvent source UUID" - }, - "type": { - "type": "string", - "description": "CloudEvent type" - }, - "correlation": { - "type": "array", - "description": "CloudEvent correlation definitions", - "minItems": 1, - "items": { - "type": "object", - "$ref": "../correlation/correlationdef.json" - } - }, - "dataOnly": { - "type": "boolean", - "default": true, - "description": "If `true`, only the Event payload is accessible to consuming Workflow states. If `false`, both event payload and context attributes should be accessible " - }, - "kind": { - "type" : "string", - "enum": ["consumed", "produced"], - "description": "Defines the events as either being consumed or produced by the workflow. Default is consumed", - "default": "consumed" - }, - "metadata": { - "$ref": "../metadata/metadata.json" - } - }, - "if": { - "properties": { - "kind": { - "const": "consumed" - } - } - }, - "then": { - "required": [ - "name", - "source", - "type" - ] - }, - "else": { - "required": [ - "name", - "type" - ] - } -} \ No newline at end of file diff --git a/api/src/main/resources/schema/events/eventref.json b/api/src/main/resources/schema/events/eventref.json deleted file mode 100644 index 76334993..00000000 --- a/api/src/main/resources/schema/events/eventref.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.events.EventRef", - "description": "Event References", - "properties": { - "triggerEventRef": { - "type": "string", - "description": "Reference to the unique name of a 'produced' event definition" - }, - "resultEventRef": { - "type": "string", - "description": "Reference to the unique name of a 'consumed' event definition" - }, - "resultEventTimeout": { - "type": "string", - "description": "Maximum amount of time (ISO 8601 format) to wait for the result event. If not defined it should default to the actionExecutionTimeout" - }, - "data": { - "type": "string", - "description": "Expression which selects parts of the states data output to become the data of the produced event." - }, - "contextAttributes": { - "existingJavaType": "java.util.Map", - "type": "object", - "description": "Add additional extension context attributes to the produced event" - }, - "invoke": { - "type": "string", - "enum": [ - "sync", - "async" - ], - "description": "Specifies if the function should be invoked sync or async. Default is sync.", - "default": "sync" - } - }, - "required": [ - "triggerEventRef", - "resultEventRef" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/events/onevents.json b/api/src/main/resources/schema/events/onevents.json deleted file mode 100644 index 2d4ed621..00000000 --- a/api/src/main/resources/schema/events/onevents.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.events.OnEvents", - "description": "Actions to be performed on Events arrival", - "properties": { - "eventRefs": { - "type": "array", - "description": "References one or more unique event names in the defined workflow events", - "items": { - "type": "object", - "existingJavaType": "java.lang.String" - } - }, - "actionMode": { - "type": "string", - "enum": [ - "sequential", - "parallel" - ], - "description": "Specifies how actions are to be performed (in sequence of parallel)", - "default": "sequential" - }, - "actions": { - "type": "array", - "description": "Actions to be performed.", - "items": { - "type": "object", - "$ref": "../actions/action.json" - } - }, - "eventDataFilter": { - "$ref": "../filters/eventdatafilter.json" - } - }, - "required": [ - "eventRefs", - "actions" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/filters/actiondatafilter.json b/api/src/main/resources/schema/filters/actiondatafilter.json deleted file mode 100644 index 3e6c2443..00000000 --- a/api/src/main/resources/schema/filters/actiondatafilter.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.filters.ActionDataFilter", - "properties": { - "fromStateData": { - "type": "string", - "description": "Workflow expression that selects state data that the state action can use" - }, - "results": { - "type": "string", - "description": "Workflow expression that filters the actions data results" - }, - "toStateData": { - "type": "string", - "description": "Workflow expression that selects a state data element to which the action results should be added/merged into. If not specified, denote, the top-level state data element" - }, - "useResults": { - "type": "boolean", - "description": "If set to false, action data results are not added/merged to state data. In this case 'results' and 'toStateData' should be ignored. Default is true.", - "default": true - } - }, - "required": [] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/filters/eventdatafilter.json b/api/src/main/resources/schema/filters/eventdatafilter.json deleted file mode 100644 index b6fc25d7..00000000 --- a/api/src/main/resources/schema/filters/eventdatafilter.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.filters.EventDataFilter", - "properties": { - "data": { - "type": "string", - "description": "Workflow expression that filters of the event data (payload)" - }, - "toStateData": { - "type": "string", - "description": " Workflow expression that selects a state data element to which the event payload should be added/merged into. If not specified, denotes, the top-level state data element." - }, - "useData": { - "type": "boolean", - "description": "If set to false, event payload is not added/merged to state data. In this case 'data' and 'toStateData' should be ignored. Default is true.", - "default": true - } - }, - "required": [] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/filters/statedatafilter.json b/api/src/main/resources/schema/filters/statedatafilter.json deleted file mode 100644 index 0859d2d1..00000000 --- a/api/src/main/resources/schema/filters/statedatafilter.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.filters.StateDataFilter", - "properties": { - "input": { - "type": "string", - "description": "Workflow expression to filter the state data input" - }, - "output": { - "type": "string", - "description": "Workflow expression that filters the state data output" - } - }, - "required": [] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/functions/functiondef.json b/api/src/main/resources/schema/functions/functiondef.json deleted file mode 100644 index 9114f284..00000000 --- a/api/src/main/resources/schema/functions/functiondef.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.functions.FunctionDefinition", - "properties": { - "name": { - "type": "string", - "description": "Function unique name", - "minLength": 1 - }, - "operation": { - "type": "string", - "description": "If type is `rest`, #. If type is `rpc`, ##. If type is `expression`, defines the workflow expression.", - "minLength": 1 - }, - "type": { - "type": "string", - "description": "Defines the function type. Is either `rest`, `asyncapi, `rpc`, `graphql`, `odata`, `expression`, or `custom`. Default is `rest`", - "enum": [ - "rest", - "asyncapi", - "rpc", - "graphql", - "odata", - "expression", - "custom" - ], - "default": "rest" - }, - "authRef": { - "type": "string", - "description": "References an auth definition name to be used to access to resource defined in the operation parameter", - "minLength": 1 - }, - "metadata": { - "$ref": "../metadata/metadata.json" - } - }, - "required": [ - "name" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/functions/functionref.json b/api/src/main/resources/schema/functions/functionref.json deleted file mode 100644 index 731e6c12..00000000 --- a/api/src/main/resources/schema/functions/functionref.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.functions.FunctionRef", - "properties": { - "refName": { - "type": "string", - "description": "Name of the referenced function", - "minLength": 1 - }, - "arguments": { - "type": "object", - "description": "Function arguments", - "existingJavaType": "com.fasterxml.jackson.databind.JsonNode" - }, - "selectionSet": { - "type": "string", - "description": "Only used if function type is 'graphql'. A string containing a valid GraphQL selection set" - }, - "invoke": { - "type": "string", - "enum": [ - "sync", - "async" - ], - "description": "Specifies if the function should be invoked sync or async. Default is sync.", - "default": "sync" - } - }, - "required": [ - "refName" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/functions/subflowref.json b/api/src/main/resources/schema/functions/subflowref.json deleted file mode 100644 index 5eca7b17..00000000 --- a/api/src/main/resources/schema/functions/subflowref.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.functions.SubFlowRef", - "properties": { - "workflowId": { - "type": "string", - "description": "Unique id of the sub-workflow to be invoked" - }, - "version": { - "type": "string", - "description": "Version of the sub-workflow to be invoked", - "minLength": 1 - }, - "onParentComplete": { - "type": "string", - "enum": [ - "continue", - "terminate" - ], - "description": "If invoke is 'async', specifies how subflow execution should behave when parent workflow completes. Default is 'terminate'", - "default": "terminate" - }, - "invoke": { - "type": "string", - "enum": [ - "sync", - "async" - ], - "description": "Specifies if the function should be invoked sync or async. Default is sync.", - "default": "sync" - } - }, - "required": [ - "workflowId" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/metadata/metadata.json b/api/src/main/resources/schema/metadata/metadata.json deleted file mode 100644 index c56687a5..00000000 --- a/api/src/main/resources/schema/metadata/metadata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "object", - "description": "Metadata", - "existingJavaType": "java.util.Map" -} \ No newline at end of file diff --git a/api/src/main/resources/schema/produce/produceevent.json b/api/src/main/resources/schema/produce/produceevent.json deleted file mode 100644 index f094824e..00000000 --- a/api/src/main/resources/schema/produce/produceevent.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.produce.ProduceEvent", - "properties": { - "eventRef": { - "type": "string", - "description": "References a name of a defined event", - "minLength": 1 - }, - "data": { - "type": "string", - "description": "Workflow expression which selects parts of the states data output to become the data of the produced event" - }, - "contextAttributes": { - "type": "object", - "description": "Add additional event extension context attributes", - "existingJavaType": "java.util.Map" - } - }, - "required": [ - "eventRef" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/repeat/repeat.json b/api/src/main/resources/schema/repeat/repeat.json deleted file mode 100644 index 826b2787..00000000 --- a/api/src/main/resources/schema/repeat/repeat.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.repeat.Repeat", - "properties": { - "expression": { - "type": "string", - "description": "Expression evaluated against SubFlow state data. SubFlow will repeat execution as long as this expression is true or until the max property count is reached", - "minLength": 1 - }, - "checkBefore": { - "type": "boolean", - "description": "If true, the expression is evaluated before each repeat execution, if false the expression is evaluated after each repeat execution", - "default": true - }, - "max": { - "type": "integer", - "description": "Sets the maximum amount of repeat executions", - "minimum": 0 - }, - "continueOnError": { - "type": "boolean", - "description": "If true, repeats executions in a case unhandled errors propagate from the sub-workflow to this state", - "default": false - }, - "stopOnEvents": { - "type" : "array", - "description": "List referencing defined consumed workflow events. SubFlow will repeat execution until one of the defined events is consumed, or until the max property count is reached", - "items": { - "type": "object", - "existingJavaType": "java.lang.String" - } - } - }, - "required": [ - "nextState" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/retry/retrydef.json b/api/src/main/resources/schema/retry/retrydef.json deleted file mode 100644 index 9d6ea91c..00000000 --- a/api/src/main/resources/schema/retry/retrydef.json +++ /dev/null @@ -1,43 +0,0 @@ - { - "type": "object", - "javaType": "io.serverlessworkflow.api.retry.RetryDefinition", - "description": "Retry Definition", - "properties": { - "name": { - "type": "string", - "description": "Unique retry strategy name", - "minLength": 1 - }, - "delay": { - "type": "string", - "description": "Time delay between retry attempts (ISO 8601 duration format)" - }, - "maxDelay": { - "type": "string", - "description": "Maximum time delay between retry attempts (ISO 8601 duration format)" - }, - "increment": { - "type": "string", - "description": "Static value by which the delay increases during each attempt (ISO 8601 time format)" - }, - "multiplier": { - "type": "string", - "description": "Multiplier value by which interval increases during each attempt (ISO 8601 time format)" - }, - "maxAttempts": { - "type": "string", - "default": "0", - "description": "Maximum number of retry attempts. Value of 0 means no retries are performed" - }, - "jitter": { - "type": "string", - "minimum": 0.0, - "maximum": 1.0, - "description": "Absolute maximum amount of random time added or subtracted from the delay between each retry (ISO 8601 duration format)" - } - }, - "required": [ - "name", - "maxAttempts" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/schedule/schedule.json b/api/src/main/resources/schema/schedule/schedule.json deleted file mode 100644 index c384540f..00000000 --- a/api/src/main/resources/schema/schedule/schedule.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.schedule.Schedule", - "description": "Start state schedule definition", - "properties": { - "interval": { - "type": "string", - "description": "Time interval (ISO 8601 format) describing when the workflow starting state is active" - }, - "cron": { - "description": "Schedule cron definition", - "$ref": "../cron/crondef.json" - }, - "timezone": { - "type": "string", - "description": "Timezone name used to evaluate the cron expression. Not used for interval as timezone can be specified there directly. If not specified, should default to local machine timezone." - } - }, - "oneOf": [ - { - "required": [ - "interval" - ] - }, - { - "required": [ - "cron" - ] - } - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/sleep/sleep.json b/api/src/main/resources/schema/sleep/sleep.json deleted file mode 100644 index 94807a04..00000000 --- a/api/src/main/resources/schema/sleep/sleep.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.sleep.Sleep", - "properties": { - "before": { - "type": "string", - "description": "Amount of time (ISO 8601 duration format) to sleep before function/subflow invocation. Does not apply if 'eventRef' is defined." - }, - "after": { - "type": "string", - "description": "Amount of time (ISO 8601 duration format) to sleep after function/subflow invocation. Does not apply if 'eventRef' is defined." - } - }, - "required": [ - "before", - "after" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/start/start.json b/api/src/main/resources/schema/start/start.json deleted file mode 100644 index 3f1e10ee..00000000 --- a/api/src/main/resources/schema/start/start.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.start.Start", - "description": "State start definition", - "properties": { - "stateName": { - "type": "string", - "description": "Name of the starting workflow state", - "minLength": 1 - }, - "schedule": { - "description": "Define when the time/repeating intervals at which workflow instances can/should be started", - "$ref": "../schedule/schedule.json" - } - }, - "required": [ - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/states/callbackstate.json b/api/src/main/resources/schema/states/callbackstate.json deleted file mode 100644 index c8a2c5a7..00000000 --- a/api/src/main/resources/schema/states/callbackstate.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.states.CallbackState", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.State" - ], - "description": "This state is used to wait for events from event sources and then transitioning to a next state", - "extends": { - "$ref": "defaultstate.json" - }, - "properties": { - "action": { - "description": "Defines the action to be executed", - "$ref": "../actions/action.json" - }, - "eventRef": { - "type" : "string", - "description": "References an unique callback event name in the defined workflow events" - }, - "eventDataFilter": { - "description": "Callback event data filter definition", - "$ref": "../filters/eventdatafilter.json" - }, - "usedForCompensation": { - "type": "boolean", - "default": false, - "description": "If true, this state is used to compensate another state. Default is false" - } - }, - "required": [ - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/states/defaultstate.json b/api/src/main/resources/schema/states/defaultstate.json deleted file mode 100644 index 9e502276..00000000 --- a/api/src/main/resources/schema/states/defaultstate.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.states.DefaultState", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.State" - ], - "description": "Default State", - "properties": { - "id": { - "type": "string", - "description": "State unique identifier", - "minLength": 1 - }, - "name": { - "type": "string", - "description": "Unique name of the state", - "minLength": 1 - }, - "type": { - "type": "string", - "enum": [ - "event", - "operation", - "switch", - "sleep", - "parallel", - "subflow", - "inject", - "foreach", - "callback" - ], - "description": "State type" - }, - "end": { - "$ref": "../end/end.json", - "description": "Defines this states end" - }, - "stateDataFilter": { - "$ref": "../filters/statedatafilter.json", - "description": "State data filter definition" - }, - "metadata": { - "$ref": "../metadata/metadata.json" - }, - "transition": { - "$ref": "../transitions/transition.json" - }, - "onErrors": { - "type": "array", - "description": "State error handling definitions", - "items": { - "type": "object", - "$ref": "../error/error.json" - } - }, - "compensatedBy": { - "type": "string", - "minLength": 1, - "description": "Unique Name of a workflow state which is responsible for compensation of this state" - }, - "timeouts": { - "$ref": "../timeouts/timeoutsdef.json" - } - }, - "required": [ - "name", - "type" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/states/eventstate.json b/api/src/main/resources/schema/states/eventstate.json deleted file mode 100644 index e476c2ca..00000000 --- a/api/src/main/resources/schema/states/eventstate.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.states.EventState", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.State" - ], - "description": "This state is used to wait for events from event sources and then to invoke one or more functions to run in sequence or in parallel.", - "extends": { - "$ref": "defaultstate.json" - }, - "properties": { - "exclusive": { - "type": "boolean", - "default": true, - "description": "If true consuming one of the defined events causes its associated actions to be performed. If false all of the defined events must be consumed in order for actions to be performed" - }, - "onEvents": { - "type": "array", - "description": "Define what events trigger one or more actions to be performed", - "items": { - "type": "object", - "$ref": "../events/onevents.json" - } - } - }, - "required": [ - "onevents" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/states/foreachstate.json b/api/src/main/resources/schema/states/foreachstate.json deleted file mode 100644 index 06c0807f..00000000 --- a/api/src/main/resources/schema/states/foreachstate.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.states.ForEachState", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.State" - ], - "description": "Execute a set of defined actions or workflows for each element of a data array", - "extends": { - "$ref": "defaultstate.json" - }, - "properties": { - "inputCollection": { - "type": "string", - "description": "Workflow expression selecting an array element of the states data" - }, - "outputCollection": { - "type": "string", - "description": "Workflow expression specifying an array element of the states data to add the results of each iteration" - }, - "iterationParam": { - "type": "string", - "description": "Name of the iteration parameter that can be referenced in actions/workflow. For each parallel iteration, this param should contain an unique element of the inputCollection array" - }, - "batchSize": { - "type": "integer", - "default": "0", - "minimum": 0, - "description": "Specifies how many iterations may run in parallel at the same time. Used if 'mode' property is set to 'parallel' (default)" - }, - "actions": { - "type": "array", - "description": "Actions to be executed for each of the elements of inputCollection", - "items": { - "type": "object", - "$ref": "../actions/action.json" - } - }, - "usedForCompensation": { - "type": "boolean", - "default": false, - "description": "If true, this state is used to compensate another state. Default is false" - }, - "mode": { - "type": "string", - "enum": [ - "sequential", - "parallel" - ], - "description": "Specifies how iterations are to be performed (sequentially or in parallel)", - "default": "parallel" - } - }, - "oneOf": [ - { - "required": [ - "name", - "type", - "inputCollection", - "inputParameter", - "end" - ] - }, - { - "required": [ - "name", - "type", - "inputCollection", - "inputParameter", - "transition" - ] - }, - { - "required": [ - "start", - "name", - "type", - "inputCollection", - "inputParameter", - "end" - ] - }, - { - "required": [ - "start", - "name", - "type", - "inputCollection", - "inputParameter", - "transition" - ] - }, - { - "required": [ - "name", - "type", - "inputCollection", - "inputParameter", - "actions", - "end" - ] - }, - { - "required": [ - "name", - "type", - "inputCollection", - "inputParameter", - "actions", - "transition" - ] - }, - { - "required": [ - "start", - "name", - "type", - "inputCollection", - "inputParameter", - "actions", - "end" - ] - }, - { - "required": [ - "start", - "name", - "type", - "inputCollection", - "inputParameter", - "actions", - "transition" - ] - } - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/states/injectstate.json b/api/src/main/resources/schema/states/injectstate.json deleted file mode 100644 index d0d10589..00000000 --- a/api/src/main/resources/schema/states/injectstate.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.states.InjectState", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.State" - ], - "description": "Set up and inject the state's data input to data output. Does not perform any actions", - "extends": { - "$ref": "defaultstate.json" - }, - "properties": { - "data": { - "type": "object", - "description": "JSON object which can be set as states data input and can be manipulated via filters", - "existingJavaType": "com.fasterxml.jackson.databind.JsonNode" - }, - "usedForCompensation": { - "type": "boolean", - "default": false, - "description": "If true, this state is used to compensate another state. Default is false" - } - }, - "required": [ - "inject" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/states/operationstate.json b/api/src/main/resources/schema/states/operationstate.json deleted file mode 100644 index 8d8211a9..00000000 --- a/api/src/main/resources/schema/states/operationstate.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.states.OperationState", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.State" - ], - "description": "This state allows one or more functions to run in sequence or in parallel without waiting for any event.", - "extends": { - "$ref": "defaultstate.json" - }, - "properties": { - "actionMode": { - "type": "string", - "enum": [ - "sequential", - "parallel" - ], - "description": "Specifies whether functions are executed in sequence or in parallel." - }, - "actions": { - "type": "array", - "description": "Actions Definitions", - "items": { - "type": "object", - "$ref": "../actions/action.json" - } - }, - "usedForCompensation": { - "type": "boolean", - "default": false, - "description": "If true, this state is used to compensate another state. Default is false" - } - }, - "required": [ - "name", - "actionMode", - "actions" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/states/parallelstate.json b/api/src/main/resources/schema/states/parallelstate.json deleted file mode 100644 index 919c472f..00000000 --- a/api/src/main/resources/schema/states/parallelstate.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.states.ParallelState", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.State" - ], - "description": "Consists of a number of states that are executed in parallel", - "extends": { - "$ref": "defaultstate.json" - }, - "properties": { - "branches": { - "type": "array", - "description": "Branch Definitions", - "items": { - "type": "object", - "$ref": "../branches/branch.json" - } - }, - "completionType": { - "type" : "string", - "enum": ["allOf", "atLeast"], - "description": "Option types on how to complete branch execution.", - "default": "allOf" - }, - "numCompleted": { - "type": "string", - "default": "0", - "description": "Used when completionType is set to 'atLeast' to specify the minimum number of branches that must complete before the state will transition." - }, - "usedForCompensation": { - "type": "boolean", - "default": false, - "description": "If true, this state is used to compensate another state. Default is false" - } - }, - "required": [ - "branches" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/states/sleepstate.json b/api/src/main/resources/schema/states/sleepstate.json deleted file mode 100644 index d0d3ade7..00000000 --- a/api/src/main/resources/schema/states/sleepstate.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.states.SleepState", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.State" - ], - "description": "This state is used to wait for events from event sources and then transitioning to a next state", - "extends": { - "$ref": "defaultstate.json" - }, - "properties": { - "duration": { - "type": "string", - "description": "Duration (ISO 8601 duration format) to sleep" - }, - "usedForCompensation": { - "type": "boolean", - "default": false, - "description": "If true, this state is used to compensate another state. Default is false" - } - }, - "required": [ - "duration" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/states/switchstate.json b/api/src/main/resources/schema/states/switchstate.json deleted file mode 100644 index 7634c512..00000000 --- a/api/src/main/resources/schema/states/switchstate.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.states.SwitchState", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.State" - ], - "description": "Permits transitions to other states based on criteria matching", - "extends": { - "$ref": "defaultstate.json" - }, - "properties": { - "eventConditions": { - "type": "array", - "description": "Defines conditions evaluated against events", - "items": { - "type": "object", - "$ref": "../switchconditions/eventcondition.json" - } - }, - "dataConditions": { - "type": "array", - "description": "Defines conditions evaluated against state data", - "items": { - "type": "object", - "$ref": "../switchconditions/datacondition.json" - } - }, - "defaultCondition": { - "description": "Default transition of the workflow if there is no matching data conditions. Can include a transition or end definition", - "$ref": "../defaultcondition/defaultconditiondef.json" - }, - "usedForCompensation": { - "type": "boolean", - "default": false, - "description": "If true, this state is used to compensate another state. Default is false" - } - }, - "required": [ - "defaultCondition" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/switchconditions/datacondition.json b/api/src/main/resources/schema/switchconditions/datacondition.json deleted file mode 100644 index e72db3d3..00000000 --- a/api/src/main/resources/schema/switchconditions/datacondition.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.switchconditions.DataCondition", - "javaInterfaces": [ - "io.serverlessworkflow.api.interfaces.SwitchCondition" - ], - "description": "Switch state data based condition", - "properties": { - "name": { - "type": "string", - "description": "Data condition name" - }, - "condition": { - "type": "string", - "description": "Workflow expression evaluated against state data. True if results are not empty" - }, - "transition": { - "$ref": "../transitions/transition.json", - "description": "Next transition of the workflow if there is valid matches" - }, - "end": { - "$ref": "../end/end.json", - "description": "Workflow end definition" - } - }, - "oneOf": [ - { - "required": [ - "condition", - "transition" - ] - }, - { - "required": [ - "condition", - "end" - ] - } - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/switchconditions/eventcondition.json b/api/src/main/resources/schema/switchconditions/eventcondition.json deleted file mode 100644 index 887a96f7..00000000 --- a/api/src/main/resources/schema/switchconditions/eventcondition.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.switchconditions.EventCondition", - "javaInterfaces": ["io.serverlessworkflow.api.interfaces.SwitchCondition"], - "description": "Switch state data event condition", - "properties": { - "name": { - "type": "string", - "description": "Event condition name" - }, - "eventRef": { - "type" : "string", - "description": "References an unique event name in the defined workflow events" - }, - "eventDataFilter": { - "description": "Callback event data filter definition", - "$ref": "../filters/eventdatafilter.json" - }, - "transition": { - "$ref": "../transitions/transition.json", - "description": "Next transition of the workflow if there is valid matches" - }, - "end": { - "$ref": "../end/end.json", - "description": "Workflow end definition" - } - }, - "required": [ - "eventRef", - "transition" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/timeouts/stateexectimeout.json b/api/src/main/resources/schema/timeouts/stateexectimeout.json deleted file mode 100644 index 68f237e9..00000000 --- a/api/src/main/resources/schema/timeouts/stateexectimeout.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.timeouts.StateExecTimeout", - "properties": { - "single": { - "type": "string", - "description": "Single state execution timeout, not including retries (ISO 8601 duration format)", - "minLength": 1 - }, - "total": { - "type": "string", - "description": "Total state execution timeout, including retries (ISO 8601 duration format)", - "minLength": 1 - } - }, - "required": [ - "total" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/timeouts/timeoutsdef.json b/api/src/main/resources/schema/timeouts/timeoutsdef.json deleted file mode 100644 index 322c386e..00000000 --- a/api/src/main/resources/schema/timeouts/timeoutsdef.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.timeouts.TimeoutsDefinition", - "description": "Timeouts Definition", - "properties": { - "workflowExecTimeout": { - "$ref": "workflowexectimeout.json" - }, - "stateExecTimeout": { - "$ref": "stateexectimeout.json" - }, - "actionExecTimeout": { - "type": "string", - "description": "Single actions definition execution timeout duration (ISO 8601 duration format)", - "minLength": 1 - }, - "branchExecTimeout": { - "type": "string", - "description": "Single branch execution timeout duration (ISO 8601 duration format)", - "minLength": 1 - }, - "eventTimeout": { - "type": "string", - "description": "Timeout duration to wait for consuming defined events (ISO 8601 duration format)", - "minLength": 1 - } - }, - "required": [] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/timeouts/workflowexectimeout.json b/api/src/main/resources/schema/timeouts/workflowexectimeout.json deleted file mode 100644 index 9010b1e4..00000000 --- a/api/src/main/resources/schema/timeouts/workflowexectimeout.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.timeouts.WorkflowExecTimeout", - "properties": { - "duration": { - "type": "string", - "description": "Workflow execution timeout duration (ISO 8601 duration format). If not specified should be 'unlimited'", - "minLength": 1 - }, - "interrupt": { - "type": "boolean", - "description": "If `false`, workflow instance is allowed to finish current execution. If `true`, current workflow execution is abrupted.", - "default": true - }, - "runBefore": { - "type": "string", - "description": "Name of a workflow state to be executed before workflow instance is terminated", - "minLength": 1 - } - }, - "required": [ - "duration" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/transitions/transition.json b/api/src/main/resources/schema/transitions/transition.json deleted file mode 100644 index c540089f..00000000 --- a/api/src/main/resources/schema/transitions/transition.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "type": "object", - "javaType": "io.serverlessworkflow.api.transitions.Transition", - "properties": { - "produceEvents": { - "type": "array", - "description": "Array of events to be produced", - "items": { - "type": "object", - "$ref": "../produce/produceevent.json" - } - }, - "nextState": { - "type": "string", - "description": "State to transition to next", - "minLength": 1 - }, - "compensate": { - "type": "boolean", - "default": false, - "description": "If set to true, triggers workflow compensation before this transition is taken. Default is false" - } - }, - "required": [ - "nextState" - ] -} \ No newline at end of file diff --git a/api/src/main/resources/schema/workflow.json b/api/src/main/resources/schema/workflow.json deleted file mode 100644 index aa53061d..00000000 --- a/api/src/main/resources/schema/workflow.json +++ /dev/null @@ -1,174 +0,0 @@ -{ - "$id": "classpath:schema/workflow.schema.json", - "$schema": "http://json-schema.org/draft-07/schema#", - "description": "Serverless Workflow is a vendor-neutral specification for defining the model of workflows responsible for orchestrating event-driven serverless applications.", - "type": "object", - "extendsJavaClass": "io.serverlessworkflow.api.workflow.BaseWorkflow", - "javaType": "io.serverlessworkflow.api.Workflow", - "javaInterfaces": [ - "java.io.Serializable" - ], - "properties": { - "id": { - "type": "string", - "description": "Workflow unique identifier", - "minLength": 1 - }, - "key": { - "type": "string", - "description": "Workflow Domain-specific identifier" - }, - "name": { - "type": "string", - "description": "Workflow name", - "minLength": 1 - }, - "description": { - "type": "string", - "description": "Workflow description" - }, - "version": { - "type": "string", - "description": "Workflow version" - }, - "annotations": { - "type": "array", - "description": "List of helpful terms describing the workflows intended purpose, subject areas, or other important qualities", - "minItems": 1, - "items": { - "type": "string" - } - }, - "dataInputSchema": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.workflow.DataInputSchema", - "description": "Workflow data input schema" - }, - "start": { - "$ref": "start/start.json", - "description": "Defines workflow start" - }, - "specVersion": { - "type": "string", - "description": "Serverless Workflow schema version" - }, - "expressionLang": { - "type": "string", - "description": "Identifies the expression language used for workflow expressions. Default is 'jq'", - "default": "jq", - "minLength": 1 - }, - "keepActive": { - "type": "boolean", - "default": false, - "description": "If 'true', workflow instances is not terminated when there are no active execution paths. Instance can be terminated via 'terminate end definition' or reaching defined 'execTimeout'" - }, - "autoRetries": { - "type": "boolean", - "default": false, - "description": "If set to true, actions should automatically be retried on unchecked errors. Default is false" - }, - "metadata": { - "$ref": "metadata/metadata.json" - }, - "events": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.workflow.Events", - "description": "Workflow event definitions" - }, - "functions": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.workflow.Functions", - "description": "Workflow function definitions" - }, - "errors": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.workflow.Errors", - "description": "Workflow error definitions" - }, - "retries": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.workflow.Retries", - "description": "Workflow retry definitions" - }, - "secrets": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.workflow.Secrets", - "description": "Workflow secrets definitions" - }, - "constants": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.workflow.Constants", - "description": "Workflow constants definitions" - }, - "timeouts": { - "$ref": "timeouts/timeoutsdef.json" - }, - "auth": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.workflow.Auth", - "description": "Workflow Auth definitions" - }, - "states": { - "type": "array", - "description": "State Definitions", - "items": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.interfaces.State", - "anyOf": [ - { - "title": "Sleep State", - "$ref": "states/sleepstate.json" - }, - { - "title": "Event State", - "$ref": "states/eventstate.json" - }, - { - "title": "Operation State", - "$ref": "states/operationstate.json" - }, - { - "title": "Parallel State", - "$ref": "states/parallelstate.json" - }, - { - "title": "Switch State", - "$ref": "states/switchstate.json" - }, - { - "title": "Relay State", - "$ref": "states/injectstate.json" - }, - { - "title": "ForEach State", - "$ref": "states/foreachstate.json" - }, - { - "title": "Callback State", - "$ref": "states/callbackstate.json" - } - ] - } - }, - "extensions": { - "type": "array", - "description": "Workflow Extensions", - "items": { - "type": "object", - "existingJavaType": "io.serverlessworkflow.api.interfaces.Extension" - } - } - }, - "required": [ - "id", - "name", - "version", - "states" - ], - "dependencies": - { - "id": { "not": { "required": ["key"] } }, - "key": { "not": { "required": ["id"] } } - } -} diff --git a/api/src/main/resources/schema/workflow.yaml b/api/src/main/resources/schema/workflow.yaml new file mode 100644 index 00000000..f03ebe18 --- /dev/null +++ b/api/src/main/resources/schema/workflow.yaml @@ -0,0 +1,921 @@ +$id: https://serverlessworkflow.io/schemas/1.0.0-alpha1/workflow.json +$schema: http://json-schema.org/draft-07/schema +description: Serverless Workflow DSL - Workflow Schema +type: object +properties: + document: + type: object + properties: + dsl: + type: string + pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ + description: The version of the DSL used by the workflow. + namespace: + type: string + pattern: ^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ + description: The workflow's namespace. + name: + type: string + pattern: ^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ + description: The workflow's name. + version: + type: string + pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ + description: The workflow's semantic version. + title: + type: string + description: The workflow's title. + summary: + type: string + description: The workflow's Markdown summary. + tags: + type: object + description: A key/value mapping of the workflow's tags, if any. + additionalProperties: true + required: [ dsl, namespace, name, version ] + description: Documents the workflow + input: + $ref: '#/$defs/input' + description: Configures the workflow's input. + use: + type: object + properties: + authentications: + type: object + additionalProperties: + $ref: '#/$defs/authenticationPolicy' + description: The workflow's reusable authentication policies. + errors: + type: object + additionalProperties: + $ref: '#/$defs/error' + description: The workflow's reusable errors. + extensions: + type: array + items: + type: object + minProperties: 1 + maxProperties: 1 + additionalProperties: + $ref: '#/$defs/extension' + description: The workflow's extensions. + functions: + type: object + additionalProperties: + $ref: '#/$defs/task' + description: The workflow's reusable functions. + retries: + type: object + additionalProperties: + $ref: '#/$defs/retryPolicy' + description: The workflow's reusable retry policies. + secrets: + type: array + items: + type: string + description: The workflow's secrets. + description: Defines the workflow's reusable components. + do: + description: Defines the task the workflow must perform + $ref: '#/$defs/task' + timeout: + $ref: '#/$defs/timeout' + description: The workflow's timeout configuration, if any. + output: + $ref: '#/$defs/output' + description: Configures the workflow's output. + schedule: + type: object + properties: + every: + $ref: '#/$defs/duration' + description: Specifies the duration of the interval at which the workflow should be executed. + cron: + type: string + description: Specifies the schedule using a cron expression, e.g., '0 0 * * *' for daily at midnight." + after: + $ref: '#/$defs/duration' + description: Specifies a delay duration that the workflow must wait before starting again after it completes. + on: + $ref: '#/$defs/eventConsumptionStrategy' + description: Specifies the events that trigger the workflow execution. + description: Schedules the workflow +$defs: + task: + type: object + properties: + input: + $ref: '#/$defs/input' + description: Configure the task's input. + output: + $ref: '#/$defs/output' + description: Configure the task's output. + export: + $ref: '#/$defs/export' + description: Export task output to context. + timeout: + $ref: '#/$defs/timeout' + description: The task's timeout configuration, if any. + then: + $ref: '#/$defs/flowDirective' + description: The flow directive to be performed upon completion of the task. + oneOf: + - $ref: '#/$defs/callTask' + - $ref: '#/$defs/compositeTask' + - $ref: '#/$defs/emitTask' + - $ref: '#/$defs/forTask' + - $ref: '#/$defs/listenTask' + - $ref: '#/$defs/raiseTask' + - $ref: '#/$defs/runTask' + - $ref: '#/$defs/setTask' + - $ref: '#/$defs/switchTask' + - $ref: '#/$defs/tryTask' + - $ref: '#/$defs/waitTask' + callTask: + type: object + oneOf: + - properties: + call: + type: string + const: asyncapi + with: + type: object + properties: + document: + $ref: '#/$defs/externalResource' + description: The document that defines the AsyncAPI operation to call. + operationRef: + type: string + description: A reference to the AsyncAPI operation to call. + server: + type: string + description: A a reference to the server to call the specified AsyncAPI operation on. If not set, default to the first server matching the operation's channel. + message: + type: string + description: The name of the message to use. If not set, defaults to the first message defined by the operation. + binding: + type: string + description: The name of the binding to use. If not set, defaults to the first binding defined by the operation. + payload: + type: object + description: The payload to call the AsyncAPI operation with, if any. + authentication: + description: The authentication policy, if any, to use when calling the AsyncAPI operation. + oneOf: + - $ref: '#/$defs/authenticationPolicy' + - type: string + required: [ document, operationRef ] + description: Defines the AsyncAPI call to perform. + required: [ call, with ] + - properties: + call: + type: string + const: grpc + with: + type: object + properties: + proto: + $ref: '#/$defs/externalResource' + description: The proto resource that describes the GRPC service to call. + service: + type: object + properties: + name: + type: string + description: The name of the GRPC service to call. + host: + type: string + pattern: ^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ + description: The hostname of the GRPC service to call. + port: + type: integer + min: 0 + max: 65535 + description: The port number of the GRPC service to call. + authentication: + description: The endpoint's authentication policy, if any. + oneOf: + - $ref: '#/$defs/authenticationPolicy' + - type: string + required: [ name, host ] + method: + type: string + description: The name of the method to call on the defined GRPC service. + arguments: + type: object + additionalProperties: true + description: The arguments, if any, to call the method with. + required: [ proto, service, method ] + description: Defines the GRPC call to perform. + required: [ call, with ] + - properties: + call: + type: string + const: http + with: + type: object + properties: + method: + type: string + description: The HTTP method of the HTTP request to perform. + endpoint: + description: The HTTP endpoint to send the request to. + oneOf: + - $ref: '#/$defs/endpoint' + - type: string + format: uri-template + headers: + type: object + description: A name/value mapping of the headers, if any, of the HTTP request to perform. + body: + description: The body, if any, of the HTTP request to perform. + output: + type: string + enum: [ raw, content, response ] + description: The http call output format. Defaults to 'content'. + required: [ method, endpoint ] + description: Defines the HTTP call to perform. + required: [ call, with ] + - properties: + call: + type: string + const: openapi + with: + type: object + properties: + document: + $ref: '#/$defs/externalResource' + description: The document that defines the OpenAPI operation to call. + operationId: + type: string + description: The id of the OpenAPI operation to call. + parameters: + type: object + additionalProperties: true + description: A name/value mapping of the parameters of the OpenAPI operation to call. + authentication: + description: The authentication policy, if any, to use when calling the OpenAPI operation. + oneOf: + - $ref: '#/$defs/authenticationPolicy' + - type: string + output: + type: string + enum: [ raw, content, response ] + description: The http call output format. Defaults to 'content'. + required: [ document, operationId ] + description: Defines the OpenAPI call to perform. + required: [ call, with ] + - properties: + call: + type: string + not: + enum: ["asyncapi", "grpc", "http", "openapi"] + description: The name of the function to call. + with: + type: object + additionalProperties: true + description: A name/value mapping of the parameters, if any, to call the function with. + required: [ call ] + compositeTask: + type: object + required: [ execute ] + description: Serves as a pivotal orchestrator within workflow systems, enabling the seamless integration and execution of multiple subtasks to accomplish complex operations + properties: + execute: + type: object + description: Configures the task execution strategy to use + oneOf: + - required: [ concurrently ] + properties: + concurrently: + description: A list of the tasks to perform concurrently. + type: array + minItems: 2 + items: + type: object + minProperties: 1 + maxProperties: 1 + additionalProperties: + $ref: '#/$defs/task' + compete: + description: Indicates whether or not the concurrent tasks are racing against each other, with a single possible winner, which sets the composite task's output. + type: boolean + default: false + - required: [ sequentially ] + properties: + sequentially: + description: A list of the tasks to perform sequentially. + type: array + minItems: 2 + items: + type: object + minProperties: 1 + maxProperties: 1 + additionalProperties: + $ref: '#/$defs/task' + emitTask: + type: object + properties: + emit: + type: object + properties: + event: + type: object + properties: + id: + type: string + description: The event's unique identifier + source: + type: string + format: uri + description: Identifies the context in which an event happened + type: + type: string + description: This attribute contains a value describing the type of event related to the originating occurrence. + time: + type: string + format: date-time + subject: + type: string + datacontenttype: + type: string + description: Content type of data value. This attribute enables data to carry any type of content, whereby format and encoding might differ from that of the chosen event format. + dataschema: + type: string + format: uri + required: [ source, type ] + additionalProperties: true + required: [ event ] + required: [ emit ] + description: Allows workflows to publish events to event brokers or messaging systems, facilitating communication and coordination between different components and services. + flowDirective: + additionalProperties: false + anyOf: + - type: string + enum: [ continue, exit, end ] + default: continue + - type: string + forTask: + type: object + properties: + for: + type: object + properties: + each: + type: string + description: The name of the variable used to store the current item being enumerated. + default: item + in: + type: string + description: A runtime expression used to get the collection to enumerate. + at: + type: string + description: The name of the variable used to store the index of the current item being enumerated. + default: index + required: [ in ] + while: + type: string + description: A runtime expression that represents the condition, if any, that must be met for the iteration to continue. + do: + $ref: '#/$defs/task' + description: Allows workflows to iterate over a collection of items, executing a defined set of subtasks for each item in the collection. This task type is instrumental in handling scenarios such as batch processing, data transformation, and repetitive operations across datasets. + required: [ for, do ] + listenTask: + type: object + properties: + listen: + type: object + properties: + to: + $ref: '#/$defs/eventConsumptionStrategy' + description: Defines the event(s) to listen to. + required: [ to ] + required: [ listen ] + description: Provides a mechanism for workflows to await and react to external events, enabling event-driven behavior within workflow systems. + raiseTask: + type: object + properties: + raise: + type: object + properties: + error: + $ref: '#/$defs/error' + description: Defines the error to raise. + required: [ error ] + required: [ raise ] + description: Intentionally triggers and propagates errors. + runTask: + type: object + properties: + run: + type: object + oneOf: + - properties: + container: + type: object + properties: + image: + type: string + description: The name of the container image to run. + command: + type: string + description: The command, if any, to execute on the container + ports: + type: object + description: The container's port mappings, if any. + volumes: + type: object + description: The container's volume mappings, if any. + environment: + type: object + description: A key/value mapping of the environment variables, if any, to use when running the configured process. + required: [ image ] + required: [ container ] + description: Enables the execution of external processes encapsulated within a containerized environment. + - properties: + script: + type: object + properties: + language: + type: string + description: The language of the script to run. + environment: + type: object + additionalProperties: true + description: A key/value mapping of the environment variables, if any, to use when running the configured process. + oneOf: + - properties: + code: + type: string + required: [ code ] + description: The script's code. + - properties: + source: + $ref: '#/$defs/externalResource' + description: The script's resource. + required: [ code ] + required: [ language ] + required: [ script ] + description: Enables the execution of custom scripts or code within a workflow, empowering workflows to perform specialized logic, data processing, or integration tasks by executing user-defined scripts written in various programming languages. + - properties: + shell: + type: object + properties: + command: + type: string + description: The shell command to run. + arguments: + type: object + additionalProperties: true + description: A list of the arguments of the shell command to run. + environment: + type: object + additionalProperties: true + description: A key/value mapping of the environment variables, if any, to use when running the configured process. + required: [ command ] + required: [ shell ] + description: Enables the execution of shell commands within a workflow, enabling workflows to interact with the underlying operating system and perform system-level operations, such as file manipulation, environment configuration, or system administration tasks. + - properties: + workflow: + type: object + properties: + namespace: + type: string + description: The namespace the workflow to run belongs to. + name: + type: string + description: The name of the workflow to run. + version: + type: string + default: latest + description: The version of the workflow to run. Defaults to latest + input: + type: object + additionalProperties: true + description: The data, if any, to pass as input to the workflow to execute. The value should be validated against the target workflow's input schema, if specified. + required: [ namespace, name, version ] + required: [ workflow ] + description: Enables the invocation and execution of nested workflows within a parent workflow, facilitating modularization, reusability, and abstraction of complex logic or business processes by encapsulating them into standalone workflow units. + required: [ run ] + description: Provides the capability to execute external containers, shell commands, scripts, or workflows. + setTask: + type: object + properties: + set: + type: object + minProperties: 1 + additionalProperties: true + description: The data to set + required: [ set ] + description: A task used to set data + switchTask: + type: object + properties: + switch: + type: array + minItems: 1 + items: + type: object + minProperties: 1 + maxProperties: 1 + additionalProperties: + type: object + properties: + name: + type: string + description: The case's name. + when: + type: string + description: A runtime expression used to determine whether or not the case matches. + then: + $ref: '#/$defs/flowDirective' + description: The flow directive to execute when the case matches. + required: [ switch ] + description: Enables conditional branching within workflows, allowing them to dynamically select different paths based on specified conditions or criteria + tryTask: + type: object + properties: + try: + description: The task to perform. + $ref: '#/$defs/task' + catch: + type: object + properties: + errors: + type: object + as: + type: string + description: The name of the runtime expression variable to save the error as. Defaults to 'error'. + when: + type: string + description: A runtime expression used to determine whether or not to catch the filtered error + exceptWhen: + type: string + description: A runtime expression used to determine whether or not to catch the filtered error + retry: + $ref: '#/$defs/retryPolicy' + description: The retry policy to use, if any, when catching errors. + do: + description: The definition of the task to run when catching an error. + $ref: '#/$defs/task' + required: [ try, catch ] + description: Serves as a mechanism within workflows to handle errors gracefully, potentially retrying failed tasks before proceeding with alternate ones. + waitTask: + type: object + properties: + wait: + $ref: '#/$defs/duration' + description: The amount of time to wait. + required: [ wait ] + description: Allows workflows to pause or delay their execution for a specified period of time. + authenticationPolicy: + type: object + oneOf: + - properties: + basic: + type: object + properties: + username: + type: string + description: The username to use. + password: + type: string + description: The password to use. + required: [ username, password ] + required: [ basic ] + description: Use basic authentication. + - properties: + bearer: + type: object + properties: + token: + type: string + description: The bearer token to use. + required: [ token ] + required: [ bearer ] + description: Use bearer authentication. + - properties: + oauth2: + type: object + properties: + authority: + type: string + format: uri + description: The URI that references the OAuth2 authority to use. + grant: + type: string + description: The grant type to use. + client: + type: object + properties: + id: + type: string + description: The client id to use. + secret: + type: string + description: The client secret to use, if any. + required: [ id ] + scopes: + type: array + items: + type: string + description: The scopes, if any, to request the token for. + audiences: + type: array + items: + type: string + description: The audiences, if any, to request the token for. + username: + type: string + description: The username to use. Used only if the grant type is Password. + password: + type: string + description: The password to use. Used only if the grant type is Password. + subject: + $ref: '#/$defs/oauth2Token' + description: The security token that represents the identity of the party on behalf of whom the request is being made. + actor: + $ref: '#/$defs/oauth2Token' + description: The security token that represents the identity of the acting party. + required: [ authority, grant, client ] + required: [ oauth2 ] + description: Use OAUTH2 authentication. + description: Defines an authentication policy. + oauth2Token: + type: object + properties: + token: + type: string + description: The security token to use to use. + type: + type: string + description: The type of the security token to use to use. + required: [ token, type ] + duration: + type: object + minProperties: 1 + properties: + days: + type: integer + description: Number of days, if any. + hours: + type: integer + description: Number of days, if any. + minutes: + type: integer + description: Number of minutes, if any. + seconds: + type: integer + description: Number of seconds, if any. + milliseconds: + type: integer + description: Number of milliseconds, if any. + description: The definition of a duration. + error: + type: object + properties: + type: + type: string + format: uri + description: A URI reference that identifies the error type. + status: + type: integer + description: The status code generated by the origin for this occurrence of the error. + instance: + type: string + format: uri + description: A JSON Pointer used to reference the component the error originates from. + title: + type: string + description: A short, human-readable summary of the error. + detail: + type: string + description: A human-readable explanation specific to this occurrence of the error. + required: [ type, status, instance ] + endpoint: + type: object + properties: + uri: + type: string + format: uri-template + description: The endpoint's URI. + authentication: + description: The authentication policy to use. + oneOf: + - $ref: '#/$defs/authenticationPolicy' + - type: string + required: [ uri ] + eventConsumptionStrategy: + type: object + oneOf: + - properties: + all: + type: array + items: + $ref: '#/$defs/eventFilter' + description: A list containing all the events that must be consumed. + required: [ all ] + - properties: + any: + type: array + items: + $ref: '#/$defs/eventFilter' + description: A list containing any of the events to consume. + required: [ any ] + - properties: + one: + $ref: '#/$defs/eventFilter' + description: The single event to consume. + required: [ one ] + eventFilter: + type: object + properties: + with: + type: object + minProperties: 1 + properties: + id: + type: string + description: The event's unique identifier + source: + type: string + description: Identifies the context in which an event happened + type: + type: string + description: This attribute contains a value describing the type of event related to the originating occurrence. + time: + type: string + subject: + type: string + datacontenttype: + type: string + description: Content type of data value. This attribute enables data to carry any type of content, whereby format and encoding might differ from that of the chosen event format. + dataschema: + type: string + additionalProperties: true + description: An event filter is a mechanism used to selectively process or handle events based on predefined criteria, such as event type, source, or specific attributes. + correlate: + type: object + additionalProperties: + type: object + properties: + from: + type: string + description: A runtime expression used to extract the correlation value from the filtered event. + expect: + type: string + description: A constant or a runtime expression, if any, used to determine whether or not the extracted correlation value matches expectations. If not set, the first extracted value will be used as the correlation's expectation. + required: [ from ] + description: A correlation is a link between events and data, established by mapping event attributes to specific data attributes, allowing for coordinated processing or handling based on event characteristics. + required: [ with ] + description: An event filter is a mechanism used to selectively process or handle events based on predefined criteria, such as event type, source, or specific attributes. + extension: + type: object + properties: + extend: + type: string + enum: [ call, composite, emit, for, listen, raise, run, set, switch, try, wait, all ] + description: The type of task to extend. + when: + type: string + description: A runtime expression, if any, used to determine whether or not the extension should apply in the specified context. + before: + description: The task to execute before the extended task, if any. + $ref: '#/$defs/task' + after: + description: The task to execute after the extended task, if any. + $ref: '#/$defs/task' + required: [ extend ] + description: The definition of a an extension. + externalResource: + type: object + properties: + uri: + type: string + format: uri + description: The endpoint's URI. + authentication: + description: The authentication policy to use. + oneOf: + - $ref: '#/$defs/authenticationPolicy' + - type: string + name: + type: string + description: The external resource's name, if any. + required: [ uri ] + input: + type: object + properties: + schema: + $ref: '#/$defs/schema' + description: The schema used to describe and validate the input of the workflow or task. + from: + type: string + description: A runtime expression, if any, used to mutate and/or filter the input of the workflow or task. + description: Configures the input of a workflow or task. + output: + type: object + properties: + schema: + $ref: '#/$defs/schema' + description: The schema used to describe and validate the output of the workflow or task. + as: + type: string + description: A runtime expression, if any, used to mutate and/or filter the output of the workflow or task. + description: Configures the output of a workflow or task. + export: + type: object + properties: + schema: + $ref: '#/$defs/schema' + description: The schema used to describe and validate the workflow context. + as: + type: string + description: A runtime expression, if any, used to export the output data to the context. + description: Set the content of the context. + retryPolicy: + type: object + properties: + when: + type: string + description: A runtime expression, if any, used to determine whether or not to retry running the task, in a given context. + exceptWhen: + type: string + description: A runtime expression used to determine whether or not to retry running the task, in a given context. + delay: + $ref: '#/$defs/duration' + description: The duration to wait between retry attempts. + backoff: + type: object + oneOf: + - properties: + constant: + type: object + description: The definition of the constant backoff to use, if any. + required: [ constant ] + - properties: + exponential: + type: object + description: The definition of the exponential backoff to use, if any. + required: [ exponential ] + - properties: + linear: + type: object + description: The definition of the linear backoff to use, if any. + required: [ linear ] + description: The retry duration backoff. + limit: + type: object + properties: + attempt: + type: object + properties: + count: + type: integer + description: The maximum amount of retry attempts, if any. + duration: + $ref: '#/$defs/duration' + description: The maximum duration for each retry attempt. + duration: + $ref: '#/$defs/duration' + description: The duration limit, if any, for all retry attempts. + description: The retry limit, if any + jitter: + type: object + properties: + from: + $ref: '#/$defs/duration' + description: The minimum duration of the jitter range + to: + $ref: '#/$defs/duration' + description: The maximum duration of the jitter range + required: [ from, to ] + description: The parameters, if any, that control the randomness or variability of the delay between retry attempts. + description: Defines a retry policy. + schema: + type: object + properties: + format: + type: string + default: json + description: The schema's format. Defaults to 'json'. The (optional) version of the format can be set using `{format}:{version}`. + oneOf: + - properties: + document: + description: The schema's inline definition. + required: [ document ] + - properties: + resource: + $ref: '#/$defs/externalResource' + description: The schema's external resource. + required: [ resource ] + description: Represents the definition of a schema. + timeout: + type: object + properties: + after: + $ref: '#/$defs/duration' + description: The duration after which to timeout. + required: [ after ] + description: The definition of a timeout. +required: [ document, do ] \ No newline at end of file diff --git a/api/src/test/java/io/serverlessworkflow/api/FeaturesTest.java b/api/src/test/java/io/serverlessworkflow/api/FeaturesTest.java new file mode 100644 index 00000000..de2591a3 --- /dev/null +++ b/api/src/test/java/io/serverlessworkflow/api/FeaturesTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import static io.serverlessworkflow.api.WorkflowReader.readWorkflow; +import static io.serverlessworkflow.api.WorkflowReader.readWorkflowFromClasspath; +import static io.serverlessworkflow.api.WorkflowWriter.writeWorkflow; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import io.serverlessworkflow.api.types.Workflow; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class FeaturesTest { + + @ParameterizedTest + @ValueSource( + strings = { + "features/callHttp.yaml", + "features/callOpenAPI.yaml", + "features/composite.yaml", + "features/data-flow.yaml", + "features/emit.yaml", + "features/flow.yaml", + "features/for.yaml", + "features/raise.yaml", + "features/set.yaml", + "features/switch.yaml", + "features/try.yaml" + }) + public void testSpecFeaturesParsing(String workflowLocation) throws IOException { + Workflow workflow = readWorkflowFromClasspath(workflowLocation); + assertWorkflow(workflow); + assertWorkflow(writeAndReadInMemory(workflow)); + } + + private static Workflow writeAndReadInMemory(Workflow workflow) throws IOException { + byte[] bytes; + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + writeWorkflow(out, workflow, WorkflowFormat.JSON); + bytes = out.toByteArray(); + } + try (ByteArrayInputStream in = new ByteArrayInputStream(bytes)) { + return readWorkflow(in, WorkflowFormat.JSON); + } + } + + private static void assertWorkflow(Workflow workflow) { + assertNotNull(workflow); + assertNotNull(workflow.getDocument()); + assertNotNull(workflow.getDo()); + } +} diff --git a/api/src/test/java/io/serverlessworkflow/api/test/CodegenTest.java b/api/src/test/java/io/serverlessworkflow/api/test/CodegenTest.java deleted file mode 100644 index 885d87b9..00000000 --- a/api/src/test/java/io/serverlessworkflow/api/test/CodegenTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.test; - -import static org.assertj.core.api.Assertions.assertThat; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.test.utils.WorkflowTestUtils; -import org.junit.jupiter.api.Test; - -class CodegenTest { - - @Test - void collectionsShouldNotBeInitializedByDefault() { - Workflow workflow = - Workflow.fromSource(WorkflowTestUtils.readWorkflowFile("/features/functionrefs.json")); - assertThat(workflow.getAnnotations()).isNull(); - } -} diff --git a/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java b/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java deleted file mode 100644 index 25159d50..00000000 --- a/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java +++ /dev/null @@ -1,965 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.test; - -import static org.junit.jupiter.api.Assertions.*; - -import com.fasterxml.jackson.databind.JsonNode; -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.actions.Action; -import io.serverlessworkflow.api.auth.AuthDefinition; -import io.serverlessworkflow.api.branches.Branch; -import io.serverlessworkflow.api.defaultdef.DefaultConditionDefinition; -import io.serverlessworkflow.api.end.End; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.api.events.EventRef; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.functions.FunctionRef; -import io.serverlessworkflow.api.functions.SubFlowRef; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.retry.RetryDefinition; -import io.serverlessworkflow.api.states.EventState; -import io.serverlessworkflow.api.states.OperationState; -import io.serverlessworkflow.api.states.ParallelState; -import io.serverlessworkflow.api.states.SwitchState; -import io.serverlessworkflow.api.switchconditions.DataCondition; -import io.serverlessworkflow.api.test.utils.WorkflowTestUtils; -import io.serverlessworkflow.api.timeouts.WorkflowExecTimeout; -import io.serverlessworkflow.api.workflow.*; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -public class MarkupToWorkflowTest { - - @ParameterizedTest - @ValueSource( - strings = { - "/examples/applicantrequest.json", - "/examples/applicantrequest.yml", - "/examples/carauctionbids.json", - "/examples/carauctionbids.yml", - "/examples/creditcheck.json", - "/examples/creditcheck.yml", - "/examples/eventbasedgreeting.json", - "/examples/eventbasedgreeting.yml", - "/examples/finalizecollegeapplication.json", - "/examples/finalizecollegeapplication.yml", - "/examples/greeting.json", - "/examples/greeting.yml", - "/examples/helloworld.json", - "/examples/helloworld.yml", - "/examples/jobmonitoring.json", - "/examples/jobmonitoring.yml", - "/examples/monitorpatient.json", - "/examples/monitorpatient.yml", - "/examples/parallel.json", - "/examples/parallel.yml", - "/examples/provisionorder.json", - "/examples/provisionorder.yml", - "/examples/sendcloudevent.json", - "/examples/sendcloudevent.yml", - "/examples/solvemathproblems.json", - "/examples/solvemathproblems.yml", - "/examples/foreachstatewithactions.json", - "/examples/foreachstatewithactions.yml", - "/examples/periodicinboxcheck.json", - "/examples/periodicinboxcheck.yml", - "/examples/vetappointmentservice.json", - "/examples/vetappointmentservice.yml", - "/examples/eventbasedtransition.json", - "/examples/eventbasedtransition.yml", - "/examples/roomreadings.json", - "/examples/roomreadings.yml", - "/examples/checkcarvitals.json", - "/examples/checkcarvitals.yml", - "/examples/booklending.json", - "/examples/booklending.yml" - }) - public void testSpecExamplesParsing(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - assertTrue(workflow.getStates().size() > 0); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/applicantrequest.json", "/features/applicantrequest.yml"}) - public void testSpecFeatureFunctionRef(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNull(workflow.getKey()); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - assertTrue(workflow.getStates().size() > 0); - - assertNotNull(workflow.getFunctions()); - assertEquals(1, workflow.getFunctions().getFunctionDefs().size()); - } - - @ParameterizedTest - @ValueSource( - strings = { - "/features/applicantrequest-with-key.json", - "/features/applicantrequest-with-key.yml" - }) - public void testSpecFeatureFunctionRefWithKey(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertEquals("applicant-key-request", workflow.getKey()); - assertNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - assertTrue(workflow.getStates().size() > 0); - - assertNotNull(workflow.getFunctions()); - assertEquals(1, workflow.getFunctions().getFunctionDefs().size()); - } - - @ParameterizedTest - @ValueSource( - strings = { - "/features/applicantrequest-with-id-and-key.json", - "/features/applicantrequest-with-id-and-key.yml" - }) - public void testSpecFeatureFunctionRefWithIdAndKey(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertEquals("applicant-key-request", workflow.getKey()); - assertEquals("applicant-with-key-and-id", workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - assertTrue(workflow.getStates().size() > 0); - - assertNotNull(workflow.getFunctions()); - assertEquals(1, workflow.getFunctions().getFunctionDefs().size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/vetappointment.json", "/features/vetappointment.yml"}) - public void testSpecFreatureEventRef(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - assertTrue(workflow.getStates().size() > 0); - - assertNotNull(workflow.getEvents()); - assertEquals(2, workflow.getEvents().getEventDefs().size()); - - assertNotNull(workflow.getRetries()); - assertEquals(1, workflow.getRetries().getRetryDefs().size()); - } - - @ParameterizedTest - @ValueSource( - strings = {"/features/compensationworkflow.json", "/features/compensationworkflow.yml"}) - public void testSpecFreatureCompensation(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(2, workflow.getStates().size()); - - State firstState = workflow.getStates().get(0); - assertTrue(firstState instanceof EventState); - assertNotNull(firstState.getCompensatedBy()); - assertEquals("CancelPurchase", firstState.getCompensatedBy()); - - State secondState = workflow.getStates().get(1); - assertTrue(secondState instanceof OperationState); - OperationState operationState = (OperationState) secondState; - - assertTrue(operationState.isUsedForCompensation()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/functiontypes.json", "/features/functiontypes.yml"}) - public void testFunctionTypes(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - - State state = workflow.getStates().get(0); - assertTrue(state instanceof OperationState); - - List functionDefs = workflow.getFunctions().getFunctionDefs(); - assertNotNull(functionDefs); - assertEquals(2, functionDefs.size()); - - FunctionDefinition restFunc = functionDefs.get(0); - assertEquals(restFunc.getType(), FunctionDefinition.Type.REST); - - FunctionDefinition restFunc2 = functionDefs.get(1); - assertEquals(restFunc2.getType(), FunctionDefinition.Type.EXPRESSION); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/transitions.json", "/features/transitions.yml"}) - public void testTransitions(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - - State state = workflow.getStates().get(0); - assertTrue(state instanceof SwitchState); - - SwitchState switchState = (SwitchState) workflow.getStates().get(0); - assertNotNull(switchState.getDataConditions()); - List dataConditions = switchState.getDataConditions(); - - assertEquals(2, dataConditions.size()); - - DataCondition cond1 = switchState.getDataConditions().get(0); - assertNotNull(cond1.getTransition()); - assertEquals("StartApplication", cond1.getTransition().getNextState()); - assertNotNull(cond1.getTransition().getProduceEvents()); - assertTrue(cond1.getTransition().getProduceEvents().isEmpty()); - assertFalse(cond1.getTransition().isCompensate()); - - DataCondition cond2 = switchState.getDataConditions().get(1); - assertNotNull(cond2.getTransition()); - assertEquals("RejectApplication", cond2.getTransition().getNextState()); - assertNotNull(cond2.getTransition().getProduceEvents()); - assertEquals(1, cond2.getTransition().getProduceEvents().size()); - assertNotNull(cond2.getTransition().getProduceEvents().get(0).getContextAttributes()); - Map contextAttributes = - cond2.getTransition().getProduceEvents().get(0).getContextAttributes(); - assertEquals(2, contextAttributes.size()); - assertEquals("IN", contextAttributes.get("order_location")); - assertEquals("online", contextAttributes.get("order_type")); - assertFalse(cond2.getTransition().isCompensate()); - - assertNotNull(switchState.getDefaultCondition()); - DefaultConditionDefinition defaultDefinition = switchState.getDefaultCondition(); - assertNotNull(defaultDefinition.getTransition()); - assertEquals("RejectApplication", defaultDefinition.getTransition().getNextState()); - assertNull(defaultDefinition.getTransition().getProduceEvents()); - assertTrue(defaultDefinition.getTransition().isCompensate()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/functionrefs.json", "/features/functionrefs.yml"}) - public void testFunctionRefs(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - - State state = workflow.getStates().get(0); - assertTrue(state instanceof OperationState); - - OperationState operationState = (OperationState) workflow.getStates().get(0); - assertNotNull(operationState.getActions()); - assertEquals(2, operationState.getActions().size()); - - Action action1 = operationState.getActions().get(0); - assertNotNull(action1); - assertNotNull(action1.getFunctionRef()); - FunctionRef functionRef1 = action1.getFunctionRef(); - assertEquals("creditCheckFunction", functionRef1.getRefName()); - assertNull(functionRef1.getArguments()); - - Action action2 = operationState.getActions().get(1); - assertNotNull(action2); - assertNotNull(action2.getFunctionRef()); - FunctionRef functionRef2 = action2.getFunctionRef(); - assertEquals("sendRejectionEmailFunction", functionRef2.getRefName()); - assertEquals(1, functionRef2.getArguments().size()); - assertEquals("${ .customer }", functionRef2.getArguments().get("applicant").asText()); - } - - @ParameterizedTest - @ValueSource( - strings = {"/features/keepactiveexectimeout.json", "/features/keepactiveexectimeout.yml"}) - public void testKeepActiveExecTimeout(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertTrue(workflow.isKeepActive()); - assertNotNull(workflow.getTimeouts()); - assertNotNull(workflow.getTimeouts().getWorkflowExecTimeout()); - - WorkflowExecTimeout execTimeout = workflow.getTimeouts().getWorkflowExecTimeout(); - assertEquals("PT1H", execTimeout.getDuration()); - assertEquals("GenerateReport", execTimeout.getRunBefore()); - } - - @ParameterizedTest - @ValueSource( - strings = {"/features/functionrefjsonparams.json", "/features/functionrefjsonparams.yml"}) - public void testFunctionRefJsonParams(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - assertTrue(workflow.getStates().get(0) instanceof OperationState); - - OperationState operationState = (OperationState) workflow.getStates().get(0); - assertNotNull(operationState.getActions()); - assertEquals(1, operationState.getActions().size()); - List actions = operationState.getActions(); - assertNotNull(actions.get(0).getFunctionRef()); - assertEquals("addPet", actions.get(0).getFunctionRef().getRefName()); - - JsonNode params = actions.get(0).getFunctionRef().getArguments(); - assertNotNull(params); - assertEquals(4, params.size()); - assertEquals(123, params.get("id").intValue()); - assertEquals("My Address, 123 MyCity, MyCountry", params.get("address").asText()); - assertEquals("${ .owner.name }", params.get("owner").asText()); - assertEquals("Pluto", params.get("body").get("name").asText()); - assertEquals("${ .pet.tagnumber }", params.get("body").get("tag").asText()); - } - - @ParameterizedTest - @ValueSource( - strings = {"/features/functionrefnoparams.json", "/features/functionrefnoparams.yml"}) - public void testFunctionRefNoParams(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - assertTrue(workflow.getStates().get(0) instanceof OperationState); - - OperationState operationState = (OperationState) workflow.getStates().get(0); - assertNotNull(operationState.getActions()); - assertEquals(2, operationState.getActions().size()); - List actions = operationState.getActions(); - assertNotNull(actions.get(0).getFunctionRef()); - assertNotNull(actions.get(1).getFunctionRef()); - assertEquals("addPet", actions.get(0).getFunctionRef().getRefName()); - assertEquals("addPet", actions.get(1).getFunctionRef().getRefName()); - - JsonNode params = actions.get(0).getFunctionRef().getArguments(); - assertNull(params); - JsonNode params2 = actions.get(1).getFunctionRef().getArguments(); - assertNull(params2); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/simpleschedule.json", "/features/simpleschedule.yml"}) - public void testSimplifiedSchedule(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - - assertNotNull(workflow.getStart()); - assertNotNull(workflow.getStart().getSchedule()); - - assertEquals( - "2020-03-20T09:00:00Z/2020-03-20T15:00:00Z", - workflow.getStart().getSchedule().getInterval()); - - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/simplecron.json", "/features/simplecron.yml"}) - public void testSimplifiedCron(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - - assertNotNull(workflow.getStart()); - assertNotNull(workflow.getStart().getSchedule()); - - assertEquals("0 0/15 * * * ?", workflow.getStart().getSchedule().getCron().getExpression()); - - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(2, workflow.getStates().size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/expressionlang.json", "/features/expressionlang.yml"}) - public void testExpressionLang(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getExpressionLang()); - assertEquals("abc", workflow.getExpressionLang()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/shortstart.json", "/features/shortstart.yml"}) - public void testShortStart(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStart()); - assertEquals("TestFunctionRefs", workflow.getStart().getStateName()); - assertNull(workflow.getStart().getSchedule()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/longstart.json", "/features/longstart.yml"}) - public void testLongStart(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStart()); - assertEquals("TestFunctionRefs", workflow.getStart().getStateName()); - assertNotNull(workflow.getStart().getSchedule()); - assertNotNull(workflow.getStart().getSchedule().getCron()); - assertEquals("0 0/15 * * * ?", workflow.getStart().getSchedule().getCron().getExpression()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/retriesprops.json", "/features/retriesprops.yml"}) - public void testRetriesProps(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getRetries()); - assertNotNull(workflow.getStates()); - - Retries retries = workflow.getRetries(); - assertNotNull(retries.getRetryDefs()); - assertEquals(1, retries.getRetryDefs().size()); - - RetryDefinition retryDefinition = retries.getRetryDefs().get(0); - assertEquals("Test Retries", retryDefinition.getName()); - assertEquals("PT1M", retryDefinition.getDelay()); - assertEquals("PT2M", retryDefinition.getMaxDelay()); - assertEquals("PT2S", retryDefinition.getIncrement()); - assertEquals("1.2", retryDefinition.getMultiplier()); - assertEquals("20", retryDefinition.getMaxAttempts()); - assertEquals("0.4", retryDefinition.getJitter()); - } - - @ParameterizedTest - @ValueSource( - strings = { - "/features/datainputschemastring.json", - "/features/datainputschemastring.yml", - "/features/datainputschemaobjstring.json", - "/features/datainputschemaobjstring.yml" - }) - public void testDataInputSchemaFromString(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - DataInputSchema dataInputSchema = workflow.getDataInputSchema(); - assertNotNull(dataInputSchema); - assertEquals("features/somejsonschema.json", dataInputSchema.getRefValue()); - assertTrue(dataInputSchema.isFailOnValidationErrors()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/datainputschemawithnullschema.json"}) - public void testDataInputSchemaWithNullSchema(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - DataInputSchema dataInputSchema = workflow.getDataInputSchema(); - assertNotNull(dataInputSchema); - assertEquals("null", dataInputSchema.getRefValue()); - assertTrue(dataInputSchema.isFailOnValidationErrors()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/datainputschemaobj.json", "/features/datainputschemaobj.yml"}) - public void testDataInputSchemaFromObject(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getDataInputSchema()); - DataInputSchema dataInputSchema = workflow.getDataInputSchema(); - assertNotNull(dataInputSchema.getSchemaDef()); - - JsonNode schemaObj = dataInputSchema.getSchemaDef(); - assertNotNull(schemaObj.get("properties")); - JsonNode properties = schemaObj.get("properties"); - assertNotNull(properties.get("firstName")); - JsonNode typeNode = properties.get("firstName"); - JsonNode stringNode = typeNode.get("type"); - assertEquals("string", stringNode.asText()); - assertFalse(dataInputSchema.isFailOnValidationErrors()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/subflowref.json", "/features/subflowref.yml"}) - public void testSubFlowRef(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - - assertTrue(workflow.getStates().get(0) instanceof OperationState); - - OperationState operationState = (OperationState) workflow.getStates().get(0); - - List actions = operationState.getActions(); - assertNotNull(actions); - assertEquals(2, actions.size()); - - Action firstAction = operationState.getActions().get(0); - assertNotNull(firstAction.getSubFlowRef()); - SubFlowRef firstSubflowRef = firstAction.getSubFlowRef(); - assertEquals("subflowRefReference", firstSubflowRef.getWorkflowId()); - - Action secondAction = operationState.getActions().get(1); - assertNotNull(secondAction.getSubFlowRef()); - SubFlowRef secondSubflowRef = secondAction.getSubFlowRef(); - assertEquals("subflowrefworkflowid", secondSubflowRef.getWorkflowId()); - assertEquals("1.0", secondSubflowRef.getVersion()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/secrets.json", "/features/secrets.yml"}) - public void testSecrets(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getSecrets()); - Secrets secrets = workflow.getSecrets(); - assertNotNull(secrets.getSecretDefs()); - assertEquals(3, secrets.getSecretDefs().size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/constants.json", "/features/constants.yml"}) - public void testConstants(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getConstants()); - Constants constants = workflow.getConstants(); - assertNotNull(constants.getConstantsDef()); - - JsonNode constantObj = constants.getConstantsDef(); - assertNotNull(constantObj.get("Translations")); - JsonNode translationNode = constantObj.get("Translations"); - assertNotNull(translationNode.get("Dog")); - JsonNode translationDogNode = translationNode.get("Dog"); - JsonNode serbianTranslationNode = translationDogNode.get("Serbian"); - assertEquals("pas", serbianTranslationNode.asText()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/constantsRef.json", "/features/constantsRef.yml"}) - public void testConstantsRef(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getConstants()); - Constants constants = workflow.getConstants(); - assertEquals("constantValues.json", constants.getRefValue()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/timeouts.json", "/features/timeouts.yml"}) - public void testTimeouts(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getTimeouts()); - assertNotNull(workflow.getTimeouts().getWorkflowExecTimeout()); - - WorkflowExecTimeout execTimeout = workflow.getTimeouts().getWorkflowExecTimeout(); - assertEquals("PT1H", execTimeout.getDuration()); - assertEquals("GenerateReport", execTimeout.getRunBefore()); - - assertNotNull(workflow.getStates()); - assertEquals(2, workflow.getStates().size()); - assertTrue(workflow.getStates().get(0) instanceof EventState); - - EventState firstState = (EventState) workflow.getStates().get(0); - assertNotNull(firstState.getTimeouts()); - assertNotNull(firstState.getTimeouts().getStateExecTimeout()); - assertNotNull(firstState.getTimeouts().getEventTimeout()); - assertEquals("PT5M", firstState.getTimeouts().getStateExecTimeout().getTotal()); - assertEquals("PT2M", firstState.getTimeouts().getEventTimeout()); - - assertTrue(workflow.getStates().get(1) instanceof ParallelState); - ParallelState secondState = (ParallelState) workflow.getStates().get(1); - assertNotNull(secondState.getTimeouts()); - assertNotNull(secondState.getTimeouts().getStateExecTimeout()); - assertEquals("PT5M", secondState.getTimeouts().getStateExecTimeout().getTotal()); - - assertNotNull(secondState.getBranches()); - assertEquals(2, secondState.getBranches().size()); - List branches = secondState.getBranches(); - - assertNotNull(branches.get(0).getTimeouts()); - assertNotNull(branches.get(0).getTimeouts().getBranchExecTimeout()); - assertEquals("PT3S", branches.get(0).getTimeouts().getBranchExecTimeout()); - - assertNotNull(branches.get(1).getTimeouts()); - assertNotNull(branches.get(1).getTimeouts().getBranchExecTimeout()); - assertEquals("PT4S", branches.get(1).getTimeouts().getBranchExecTimeout()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/authbasic.json", "/features/authbasic.yml"}) - public void testAuthBasic(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - - assertNotNull(workflow.getAuth()); - AuthDefinition auth = workflow.getAuth().getAuthDefs().get(0); - assertNotNull(auth.getName()); - assertEquals("authname", auth.getName()); - assertNotNull(auth.getScheme()); - assertEquals("basic", auth.getScheme().value()); - assertNotNull(auth.getBasicauth()); - assertEquals("testuser", auth.getBasicauth().getUsername()); - assertEquals("testpassword", auth.getBasicauth().getPassword()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/authbearer.json", "/features/authbearer.yml"}) - public void testAuthBearer(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - - assertNotNull(workflow.getAuth()); - AuthDefinition auth = workflow.getAuth().getAuthDefs().get(0); - assertNotNull(auth.getName()); - assertEquals("authname", auth.getName()); - assertNotNull(auth.getScheme()); - assertEquals("bearer", auth.getScheme().value()); - assertNotNull(auth.getBearerauth()); - assertEquals("testtoken", auth.getBearerauth().getToken()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/authoauth.json", "/features/authoauth.yml"}) - public void testAuthOAuth(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - - assertNotNull(workflow.getAuth()); - AuthDefinition auth = workflow.getAuth().getAuthDefs().get(0); - assertNotNull(auth.getName()); - assertEquals("authname", auth.getName()); - assertNotNull(auth.getScheme()); - assertEquals("oauth2", auth.getScheme().value()); - assertNotNull(auth.getOauth()); - assertEquals("testauthority", auth.getOauth().getAuthority()); - assertEquals("clientCredentials", auth.getOauth().getGrantType().value()); - assertEquals("${ $SECRETS.clientid }", auth.getOauth().getClientId()); - assertEquals("${ $SECRETS.clientsecret }", auth.getOauth().getClientSecret()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/actionssleep.json", "/features/actionssleep.yml"}) - public void testActionsSleep(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - - State state = workflow.getStates().get(0); - assertTrue(state instanceof OperationState); - - OperationState operationState = (OperationState) workflow.getStates().get(0); - assertNotNull(operationState.getActions()); - assertEquals(2, operationState.getActions().size()); - - Action action1 = operationState.getActions().get(0); - assertNotNull(action1); - assertNotNull(action1.getFunctionRef()); - assertNotNull(action1.getSleep()); - assertEquals("PT5S", action1.getSleep().getBefore()); - assertEquals("PT10S", action1.getSleep().getAfter()); - FunctionRef functionRef1 = action1.getFunctionRef(); - assertEquals("creditCheckFunction", functionRef1.getRefName()); - assertNull(functionRef1.getArguments()); - - Action action2 = operationState.getActions().get(1); - assertNotNull(action2); - assertNotNull(action2.getFunctionRef()); - assertNotNull(action2.getSleep()); - assertEquals("PT5S", action2.getSleep().getBefore()); - assertEquals("PT10S", action2.getSleep().getAfter()); - FunctionRef functionRef2 = action2.getFunctionRef(); - assertEquals("sendRejectionEmailFunction", functionRef2.getRefName()); - assertEquals(1, functionRef2.getArguments().size()); - assertEquals("${ .customer }", functionRef2.getArguments().get("applicant").asText()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/errors.json", "/features/errors.yml"}) - public void testErrorsParams(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - assertTrue(workflow.isAutoRetries()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - - assertNotNull(workflow.getErrors()); - assertEquals(2, workflow.getErrors().getErrorDefs().size()); - - assertTrue(workflow.getStates().get(0) instanceof OperationState); - - OperationState operationState = (OperationState) workflow.getStates().get(0); - assertNotNull(operationState.getActions()); - assertEquals(1, operationState.getActions().size()); - List actions = operationState.getActions(); - assertNotNull(actions.get(0).getFunctionRef()); - assertEquals("addPet", actions.get(0).getFunctionRef().getRefName()); - assertNotNull(actions.get(0).getRetryRef()); - assertEquals("testRetry", actions.get(0).getRetryRef()); - assertNotNull(actions.get(0).getNonRetryableErrors()); - assertEquals(2, actions.get(0).getNonRetryableErrors().size()); - assertNotNull(actions.get(0).getCondition()); - assertEquals("${ .data }", actions.get(0).getCondition()); - - assertNotNull(operationState.getOnErrors()); - assertEquals(1, operationState.getOnErrors().size()); - assertNotNull(operationState.getOnErrors().get(0).getErrorRefs()); - assertEquals(2, operationState.getOnErrors().get(0).getErrorRefs().size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/continueasstring.json", "/features/continueasstring.yml"}) - public void testContinueAsString(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - - OperationState operationState = (OperationState) workflow.getStates().get(0); - assertNotNull(operationState.getEnd()); - End end = operationState.getEnd(); - assertNotNull(end.getContinueAs()); - assertNotNull(end.getContinueAs().getWorkflowId()); - assertEquals("myworkflowid", end.getContinueAs().getWorkflowId()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/continueasobject.json", "/features/continueasobject.yml"}) - public void testContinueAsObject(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - - OperationState operationState = (OperationState) workflow.getStates().get(0); - assertNotNull(operationState.getEnd()); - End end = operationState.getEnd(); - assertNotNull(end.getContinueAs()); - assertNotNull(end.getContinueAs().getWorkflowId()); - assertEquals("myworkflowid", end.getContinueAs().getWorkflowId()); - assertEquals("1.0", end.getContinueAs().getVersion()); - assertEquals("${ .data }", end.getContinueAs().getData()); - assertNotNull(end.getContinueAs().getWorkflowExecTimeout()); - assertEquals("PT1M", end.getContinueAs().getWorkflowExecTimeout().getDuration()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/invoke.json", "/features/invoke.yml"}) - public void testFunctionInvoke(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - assertNotNull(workflow.getStates()); - assertEquals(1, workflow.getStates().size()); - - OperationState operationState = (OperationState) workflow.getStates().get(0); - assertNotNull(operationState.getEnd()); - assertNotNull(operationState.getActions()); - assertEquals(3, operationState.getActions().size()); - - Action action1 = operationState.getActions().get(0); - assertNotNull(action1.getFunctionRef()); - assertNotNull(action1.getFunctionRef().getInvoke()); - assertEquals(FunctionRef.Invoke.ASYNC, action1.getFunctionRef().getInvoke()); - - Action action2 = operationState.getActions().get(1); - assertNotNull(action2.getSubFlowRef()); - assertNotNull(action2.getSubFlowRef().getOnParentComplete()); - assertEquals( - SubFlowRef.OnParentComplete.CONTINUE, action2.getSubFlowRef().getOnParentComplete()); - assertNotNull(action2.getSubFlowRef().getInvoke()); - assertEquals(SubFlowRef.Invoke.ASYNC, action2.getSubFlowRef().getInvoke()); - - Action action3 = operationState.getActions().get(2); - assertNotNull(action3.getEventRef()); - assertNotNull(action3.getEventRef().getInvoke()); - assertEquals(EventRef.Invoke.ASYNC, action3.getEventRef().getInvoke()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/annotations.json", "/features/annotations.yml"}) - public void testAnnotations(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - - assertNotNull(workflow.getAnnotations()); - List annotations = workflow.getAnnotations(); - assertEquals(4, annotations.size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/features/eventdefdataonly.json", "/features/eventdefdataonly.yml"}) - public void testEventDefDataOnly(String workflowLocation) { - Workflow workflow = Workflow.fromSource(WorkflowTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - - assertNotNull(workflow.getEvents()); - Events events = workflow.getEvents(); - assertNotNull(workflow.getEvents().getEventDefs()); - assertEquals(2, events.getEventDefs().size()); - EventDefinition eventDefOne = events.getEventDefs().get(0); - EventDefinition eventDefTwo = events.getEventDefs().get(1); - assertEquals("visaApprovedEvent", eventDefOne.getName()); - assertFalse(eventDefOne.isDataOnly()); - assertEquals("visaRejectedEvent", eventDefTwo.getName()); - assertTrue(eventDefTwo.isDataOnly()); - } -} diff --git a/api/src/test/java/io/serverlessworkflow/api/test/WorkflowToMarkupTest.java b/api/src/test/java/io/serverlessworkflow/api/test/WorkflowToMarkupTest.java deleted file mode 100644 index f9204ca9..00000000 --- a/api/src/test/java/io/serverlessworkflow/api/test/WorkflowToMarkupTest.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.test; - -import static io.serverlessworkflow.api.states.DefaultState.Type.SLEEP; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.auth.AuthDefinition; -import io.serverlessworkflow.api.auth.BasicAuthDefinition; -import io.serverlessworkflow.api.defaultdef.DefaultConditionDefinition; -import io.serverlessworkflow.api.end.End; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.produce.ProduceEvent; -import io.serverlessworkflow.api.schedule.Schedule; -import io.serverlessworkflow.api.start.Start; -import io.serverlessworkflow.api.states.SleepState; -import io.serverlessworkflow.api.states.SwitchState; -import io.serverlessworkflow.api.switchconditions.DataCondition; -import io.serverlessworkflow.api.switchconditions.EventCondition; -import io.serverlessworkflow.api.transitions.Transition; -import io.serverlessworkflow.api.workflow.Auth; -import io.serverlessworkflow.api.workflow.Constants; -import io.serverlessworkflow.api.workflow.Events; -import io.serverlessworkflow.api.workflow.Functions; -import java.util.Arrays; -import org.junit.jupiter.api.Test; - -public class WorkflowToMarkupTest { - @Test - public void testSingleState() { - - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withName("test-workflow-name") - .withVersion("1.0") - .withStart(new Start().withSchedule(new Schedule().withInterval("PT1S"))) - .withConstants(new Constants("constantsValues.json")) - .withStates( - Arrays.asList( - new SleepState() - .withName("sleepState") - .withType(SLEEP) - .withEnd( - new End() - .withTerminate(true) - .withCompensate(true) - .withProduceEvents( - Arrays.asList(new ProduceEvent().withEventRef("someEvent")))) - .withDuration("PT1M"))); - - assertNotNull(workflow); - assertNotNull(workflow.getStart()); - Constants constants = workflow.getConstants(); - assertNotNull(constants); - assertEquals("constantsValues.json", constants.getRefValue()); - assertEquals(1, workflow.getStates().size()); - State state = workflow.getStates().get(0); - assertTrue(state instanceof SleepState); - assertNotNull(state.getEnd()); - assertNotNull(Workflow.toJson(workflow)); - assertNotNull(Workflow.toYaml(workflow)); - } - - @Test - public void testSingleFunction() { - - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withName("test-workflow-name") - .withVersion("1.0") - .withStart(new Start()) - .withFunctions( - new Functions( - Arrays.asList( - new FunctionDefinition() - .withName("testFunction") - .withOperation("testSwaggerDef#testOperationId")))) - .withStates( - Arrays.asList( - new SleepState() - .withName("delayState") - .withType(SLEEP) - .withEnd(new End()) - .withDuration("PT1M"))); - - assertNotNull(workflow); - assertNotNull(workflow.getStart()); - assertEquals(1, workflow.getStates().size()); - State state = workflow.getStates().get(0); - assertTrue(state instanceof SleepState); - assertNotNull(workflow.getFunctions()); - assertEquals(1, workflow.getFunctions().getFunctionDefs().size()); - assertEquals("testFunction", workflow.getFunctions().getFunctionDefs().get(0).getName()); - - assertNotNull(Workflow.toJson(workflow)); - assertNotNull(Workflow.toYaml(workflow)); - } - - @Test - public void testSingleEvent() { - - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withName("test-workflow-name") - .withVersion("1.0") - .withStart(new Start()) - .withEvents( - new Events( - Arrays.asList( - new EventDefinition() - .withName("testEvent") - .withSource("testSource") - .withType("testType") - .withKind(EventDefinition.Kind.PRODUCED)))) - .withFunctions( - new Functions( - Arrays.asList( - new FunctionDefinition() - .withName("testFunction") - .withOperation("testSwaggerDef#testOperationId")))) - .withStates( - Arrays.asList( - new SleepState() - .withName("delayState") - .withType(SLEEP) - .withEnd(new End()) - .withDuration("PT1M"))); - - assertNotNull(workflow); - assertNotNull(workflow.getStart()); - assertEquals(1, workflow.getStates().size()); - State state = workflow.getStates().get(0); - assertTrue(state instanceof SleepState); - assertNotNull(workflow.getFunctions()); - assertEquals(1, workflow.getFunctions().getFunctionDefs().size()); - assertEquals("testFunction", workflow.getFunctions().getFunctionDefs().get(0).getName()); - assertNotNull(workflow.getEvents()); - assertEquals(1, workflow.getEvents().getEventDefs().size()); - assertEquals("testEvent", workflow.getEvents().getEventDefs().get(0).getName()); - assertEquals( - EventDefinition.Kind.PRODUCED, workflow.getEvents().getEventDefs().get(0).getKind()); - - assertNotNull(Workflow.toJson(workflow)); - assertNotNull(Workflow.toYaml(workflow)); - } - - @Test - public void testAuth() { - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withName("test-workflow-name") - .withVersion("1.0") - .withStart(new Start()) - .withAuth( - new Auth( - new AuthDefinition() - .withName("authname") - .withScheme(AuthDefinition.Scheme.BASIC) - .withBasicauth( - new BasicAuthDefinition() - .withUsername("testuser") - .withPassword("testPassword")))); - - assertNotNull(workflow); - assertNotNull(workflow.getAuth()); - assertNotNull(workflow.getAuth().getAuthDefs().get(0)); - assertEquals("authname", workflow.getAuth().getAuthDefs().get(0).getName()); - assertNotNull(workflow.getAuth().getAuthDefs().get(0).getScheme()); - assertEquals("basic", workflow.getAuth().getAuthDefs().get(0).getScheme().value()); - assertNotNull(workflow.getAuth().getAuthDefs().get(0).getBasicauth()); - assertEquals("testuser", workflow.getAuth().getAuthDefs().get(0).getBasicauth().getUsername()); - assertEquals( - "testPassword", workflow.getAuth().getAuthDefs().get(0).getBasicauth().getPassword()); - } - - @Test - public void testSwitchConditionWithTransition() { - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withName("test-workflow-name") - .withVersion("1.0") - .withSpecVersion("0.8") - .withStates( - Arrays.asList( - new SwitchState() - .withDataConditions( - Arrays.asList( - new DataCondition() - .withCondition("test-condition") - .withTransition( - new Transition().withNextState("test-next-state")))) - .withDefaultCondition( - new DefaultConditionDefinition() - .withTransition(new Transition("test-next-state-default"))))); - assertNotNull(Workflow.toJson(workflow)); - assertNotNull(Workflow.toYaml(workflow)); - } - - @Test - public void testSwitchConditionWithEnd() { - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withName("test-workflow-name") - .withVersion("1.0") - .withSpecVersion("0.8") - .withStates( - Arrays.asList( - new SwitchState() - .withEventConditions(Arrays.asList(new EventCondition().withEnd(new End()))) - .withDefaultCondition( - new DefaultConditionDefinition().withEnd(new End())))); - assertNotNull(Workflow.toJson(workflow)); - assertNotNull(Workflow.toYaml(workflow)); - } -} diff --git a/api/src/test/java/io/serverlessworkflow/api/test/utils/WorkflowTestUtils.java b/api/src/test/java/io/serverlessworkflow/api/test/utils/WorkflowTestUtils.java deleted file mode 100644 index a21c8070..00000000 --- a/api/src/test/java/io/serverlessworkflow/api/test/utils/WorkflowTestUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.api.test.utils; - -import io.serverlessworkflow.api.mapper.JsonObjectMapper; -import io.serverlessworkflow.api.mapper.YamlObjectMapper; -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -public class WorkflowTestUtils { - private static JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(); - private static YamlObjectMapper yamlObjectMapper = new YamlObjectMapper(); - - public static final Path resourceDirectory = Paths.get("src", "test", "resources"); - public static final String absolutePath = resourceDirectory.toFile().getAbsolutePath(); - - public static Path getResourcePath(String file) { - return Paths.get(absolutePath + File.separator + file); - } - - public static InputStream getInputStreamFromPath(Path path) throws Exception { - return Files.newInputStream(path); - } - - public static String readWorkflowFile(String location) { - return readFileAsString(classpathResourceReader(location)); - } - - public static Reader classpathResourceReader(String location) { - return new InputStreamReader(WorkflowTestUtils.class.getResourceAsStream(location)); - } - - public static String readFileAsString(Reader reader) { - try { - StringBuilder fileData = new StringBuilder(1000); - char[] buf = new char[1024]; - int numRead; - while ((numRead = reader.read(buf)) != -1) { - String readData = String.valueOf(buf, 0, numRead); - fileData.append(readData); - buf = new char[1024]; - } - reader.close(); - return fileData.toString(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/api/src/test/resources/examples/applicantrequest.json b/api/src/test/resources/examples/applicantrequest.json deleted file mode 100644 index 652e361b..00000000 --- a/api/src/test/resources/examples/applicantrequest.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "id": "applicantrequest", - "key": "applicant-key-request", - "version": "1.0", - "specVersion": "0.8", - "name": "Applicant Request Decision Workflow", - "description": "Determine if applicant request is valid", - "start": "CheckApplication", - "functions": [ - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/applicationapi.json#emailRejection" - } - ], - "states":[ - { - "name":"CheckApplication", - "type":"switch", - "dataConditions": [ - { - "condition": "${ .applicants | .age >= 18 }", - "transition": "StartApplication" - }, - { - "condition": "${ .applicants | .age < 18 }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "StartApplication", - "type": "operation", - "actions": [ - { - "subFlowRef": "startApplicationWorkflowId" - } - ], - "end": true - }, - { - "name":"RejectApplication", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .applicant }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/applicantrequest.yml b/api/src/test/resources/examples/applicantrequest.yml deleted file mode 100644 index ae0db1be..00000000 --- a/api/src/test/resources/examples/applicantrequest.yml +++ /dev/null @@ -1,33 +0,0 @@ -id: applicantrequest -version: '1.0' -specVersion: '0.8' -name: Applicant Request Decision Workflow -description: Determine if applicant request is valid -start: CheckApplication -functions: - - name: sendRejectionEmailFunction - operation: http://myapis.org/applicationapi.json#emailRejection -states: - - name: CheckApplication - type: switch - dataConditions: - - condition: "${ .applicants | .age >= 18 }" - transition: StartApplication - - condition: "${ .applicants | .age < 18 }" - transition: RejectApplication - defaultCondition: - transition: RejectApplication - - name: StartApplication - type: operation - actions: - - subFlowRef: startApplicationWorkflowId - end: true - - name: RejectApplication - type: operation - actionMode: sequential - actions: - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .applicant }" - end: true diff --git a/api/src/test/resources/examples/booklending.json b/api/src/test/resources/examples/booklending.json deleted file mode 100644 index 74089115..00000000 --- a/api/src/test/resources/examples/booklending.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "id": "booklending", - "name": "Book Lending Workflow", - "version": "1.0", - "specVersion": "0.8", - "start": "Book Lending Request", - "states": [ - { - "name": "Book Lending Request", - "type": "event", - "onEvents": [ - { - "eventRefs": ["Book Lending Request Event"] - } - ], - "transition": "Get Book Status" - }, - { - "name": "Get Book Status", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "Get status for book", - "arguments": { - "bookid": "${ .book.id }" - } - } - } - ], - "transition": "Book Status Decision" - }, - { - "name": "Book Status Decision", - "type": "switch", - "dataConditions": [ - { - "name": "Book is on loan", - "condition": "${ .book.status == \"onloan\" }", - "transition": "Report Status To Lender" - }, - { - "name": "Check is available", - "condition": "${ .book.status == \"available\" }", - "transition": "Check Out Book" - } - ] - }, - { - "name": "Report Status To Lender", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "Send status to lender", - "arguments": { - "bookid": "${ .book.id }", - "message": "Book ${ .book.title } is already on loan" - } - } - } - ], - "transition": "Wait for Lender response" - }, - { - "name": "Wait for Lender response", - "type": "switch", - "eventConditions": [ - { - "name": "Hold Book", - "eventRef": "Hold Book Event", - "transition": "Request Hold" - }, - { - "name": "Decline Book Hold", - "eventRef": "Decline Hold Event", - "transition": "Cancel Request" - } - ] - }, - { - "name": "Request Hold", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "Request hold for lender", - "arguments": { - "bookid": "${ .book.id }", - "lender": "${ .lender }" - } - } - } - ], - "transition": "Wait two weeks" - }, - { - "name": "Sleep two weeks", - "type": "sleep", - "duration": "P2W", - "transition": "Get Book Status" - }, - { - "name": "Check Out Book", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "Check out book with id", - "arguments": { - "bookid": "${ .book.id }" - } - } - }, - { - "functionRef": { - "refName": "Notify Lender for checkout", - "arguments": { - "bookid": "${ .book.id }", - "lender": "${ .lender }" - } - } - } - ], - "end": true - } - ], - "functions": "file://books/lending/functions.json", - "events": "file://books/lending/events.json" -} \ No newline at end of file diff --git a/api/src/test/resources/examples/booklending.yml b/api/src/test/resources/examples/booklending.yml deleted file mode 100644 index 7a8459e2..00000000 --- a/api/src/test/resources/examples/booklending.yml +++ /dev/null @@ -1,75 +0,0 @@ -id: booklending -name: Book Lending Workflow -version: '1.0' -specVersion: '0.8' -start: Book Lending Request -states: - - name: Book Lending Request - type: event - onEvents: - - eventRefs: - - Book Lending Request Event - transition: Get Book Status - - name: Get Book Status - type: operation - actions: - - functionRef: - refName: Get status for book - arguments: - bookid: "${ .book.id }" - transition: Book Status Decision - - name: Book Status Decision - type: switch - dataConditions: - - name: Book is on loan - condition: ${ .book.status == "onloan" } - transition: Report Status To Lender - - name: Check is available - condition: ${ .book.status == "available" } - transition: Check Out Book - - name: Report Status To Lender - type: operation - actions: - - functionRef: - refName: Send status to lender - arguments: - bookid: "${ .book.id }" - message: Book ${ .book.title } is already on loan - transition: Wait for Lender response - - name: Wait for Lender response - type: switch - eventConditions: - - name: Hold Book - eventRef: Hold Book Event - transition: Request Hold - - name: Decline Book Hold - eventRef: Decline Hold Event - transition: Cancel Request - - name: Request Hold - type: operation - actions: - - functionRef: - refName: Request fold for lender - arguments: - bookid: "${ .book.id }" - lender: "${ .lender }" - transition: Wait two weeks - - name: Wait two weeks - type: sleep - duration: P2W - transition: Get Book Status - - name: Check Out Book - type: operation - actions: - - functionRef: - refName: Check out book with id - arguments: - bookid: "${ .book.id }" - - functionRef: - refName: Notify Lender for checkout - arguments: - bookid: "${ .book.id }" - lender: "${ .lender }" - end: true -functions: file://books/lending/functions.json -events: file://books/lending/events.json \ No newline at end of file diff --git a/api/src/test/resources/examples/carauctionbids.json b/api/src/test/resources/examples/carauctionbids.json deleted file mode 100644 index 7ea84d9a..00000000 --- a/api/src/test/resources/examples/carauctionbids.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "id": "handleCarAuctionBid", - "version": "1.0", - "specVersion": "0.8", - "name": "Car Auction Bidding Workflow", - "description": "Store a single bid whole the car auction is active", - "start": { - "stateName": "StoreCarAuctionBid", - "schedule": "2020-03-20T09:00:00Z/2020-03-20T15:00:00Z" - }, - "functions": [ - { - "name": "StoreBidFunction", - "operation": "http://myapis.org/carauctionapi.json#storeBid" - } - ], - "events": [ - { - "name": "CarBidEvent", - "type": "carBidMadeType", - "source": "carBidEventSource" - } - ], - "states": [ - { - "name": "StoreCarAuctionBid", - "type": "event", - "exclusive": true, - "onEvents": [ - { - "eventRefs": ["CarBidEvent"], - "actions": [{ - "functionRef": { - "refName": "StoreBidFunction", - "arguments": { - "bid": "${ .bid }" - } - } - }] - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/carauctionbids.yml b/api/src/test/resources/examples/carauctionbids.yml deleted file mode 100644 index adfe0d08..00000000 --- a/api/src/test/resources/examples/carauctionbids.yml +++ /dev/null @@ -1,28 +0,0 @@ -id: handleCarAuctionBid -version: '1.0' -specVersion: '0.8' -name: Car Auction Bidding Workflow -description: Store a single bid whole the car auction is active -start: - stateName: StoreCarAuctionBid - schedule: 2020-03-20T09:00:00Z/2020-03-20T15:00:00Z -functions: - - name: StoreBidFunction - operation: http://myapis.org/carauctionapi.json#storeBid -events: - - name: CarBidEvent - type: carBidMadeType - source: carBidEventSource -states: - - name: StoreCarAuctionBid - type: event - exclusive: true - onEvents: - - eventRefs: - - CarBidEvent - actions: - - functionRef: - refName: StoreBidFunction - arguments: - bid: "${ .bid }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/examples/checkcarvitals.json b/api/src/test/resources/examples/checkcarvitals.json deleted file mode 100644 index 973153fc..00000000 --- a/api/src/test/resources/examples/checkcarvitals.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "id": "vitalscheck", - "name": "Car Vitals Check", - "version": "1.0", - "specVersion": "0.8", - "start": "CheckVitals", - "states": [ - { - "name": "CheckVitals", - "type": "operation", - "actions": [ - { - "functionRef": "checkTirePressure" - }, - { - "functionRef": "checkOilPressure" - }, - { - "functionRef": "checkCoolantLevel" - }, - { - "functionRef": "checkBattery" - } - ], - "transition": "EvaluateChecks" - }, - { - "name": "EvaluateChecks", - "type": "switch", - "dataConditions": [ - { - "name": "Some Evaluations failed", - "condition": ".evaluations[?(@.check == 'failed')]", - "end": { - "produceEvents": [ - { - "eventRef": "DisplayFailedChecksOnDashboard", - "data": "${ .evaluations }" - } - ] - - } - } - ], - "defaultCondition": { - "transition": "WaitTwoMinutes" - } - }, - { - "name": "WaitTwoMinutes", - "type": "event", - "onEvents": [ - { - "eventRefs": ["StopVitalsCheck"], - "eventDataFilter": { - "toStateData": "${ .stopReceived }" - } - } - ], - "timeouts": { - "eventTimeout": "PT2M" - }, - "transition": "ShouldStopOrContinue" - }, - { - "name": "ShouldStopOrContinue", - "type": "switch", - "dataConditions": [ - { - "name": "Stop Event Received", - "condition": "${ has(\"stopReceived\") }", - "end": { - "produceEvents": [ - { - "eventRef": "VitalsCheckingStopped" - } - ] - - } - } - ], - "defaultCondition": { - "transition": "CheckVitals" - } - } - ], - "events": [ - { - "name": "StopVitalsCheck", - "type": "car.events", - "source": "my/car" - }, - { - "name": "VitalsCheckingStopped", - "type": "car.events", - "source": "my/car" - }, - { - "name": "DisplayFailedChecksOnDashboard", - "kind": "produced", - "type": "my.car.events" - } - ], - "functions": [ - { - "name": "checkTirePressure", - "operation": "mycarservices.json#checktirepressure" - }, - { - "name": "checkOilPressure", - "operation": "mycarservices.json#checkoilpressure" - }, - { - "name": "checkCoolantLevel", - "operation": "mycarservices.json#checkcoolantlevel" - }, - { - "name": "checkBattery", - "operation": "mycarservices.json#checkbattery" - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/checkcarvitals.yml b/api/src/test/resources/examples/checkcarvitals.yml deleted file mode 100644 index 31bd571a..00000000 --- a/api/src/test/resources/examples/checkcarvitals.yml +++ /dev/null @@ -1,64 +0,0 @@ -id: vitalscheck -name: Car Vitals Check -version: '1.0' -specVersion: '0.8' -start: CheckVitals -states: - - name: CheckVitals - type: operation - actions: - - functionRef: checkTirePressure - - functionRef: checkOilPressure - - functionRef: checkCoolantLevel - - functionRef: checkBattery - transition: EvaluateChecks - - name: EvaluateChecks - type: switch - dataConditions: - - name: Some Evaluations failed - condition: ".evaluations[?(@.check == 'failed')]" - end: - produceEvents: - - eventRef: DisplayFailedChecksOnDashboard - data: "${ .evaluations }" - defaultCondition: - transition: WaitTwoMinutes - - name: WaitTwoMinutes - type: event - onEvents: - - eventRefs: - - StopVitalsCheck - eventDataFilter: - toStateData: "${ .stopReceived }" - timeouts: - eventTimeout: PT2M - transition: ShouldStopOrContinue - - name: ShouldStopOrContinue - type: switch - dataConditions: - - name: Stop Event Received - condition: ${ has("stopReceived") } - end: - produceEvents: - - eventRef: VitalsCheckingStopped - defaultCondition: - transition: CheckVitals -events: - - name: StopVitalsCheck - type: car.events - source: my/car - - name: VitalsCheckingStopped - type: car.events - source: my/car - - name: DisplayFailedChecksOnDashboard - kind: produced - type: my.car.events -functions: - - name: checkTirePressure - operation: mycarservices.json#checktirepressure - - name: checkOilPressure - operation: mycarservices.json#checkoilpressure - - name: checkCoolantLevel - operation: mycarservices.json#checkcoolantlevel - - name: checkBattery - operation: mycarservices.json#checkbattery diff --git a/api/src/test/resources/examples/creditcheck.json b/api/src/test/resources/examples/creditcheck.json deleted file mode 100644 index 466d2eb7..00000000 --- a/api/src/test/resources/examples/creditcheck.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "id": "customercreditcheck", - "version": "1.0", - "specVersion": "0.8", - "name": "Customer Credit Check Workflow", - "description": "Perform Customer Credit Check", - "start": "CheckCredit", - "functions": [ - { - "name": "creditCheckFunction", - "operation": "http://myapis.org/creditcheckapi.json#doCreditCheck" - }, - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/creditcheckapi.json#rejectionEmail" - } - ], - "events": [ - { - "name": "CreditCheckCompletedEvent", - "type": "creditCheckCompleteType", - "source": "creditCheckSource", - "correlation": [ - { - "contextAttributeName": "customerId" - } - ] - } - ], - "states": [ - { - "name": "CheckCredit", - "type": "callback", - "action": { - "functionRef": { - "refName": "callCreditCheckMicroservice", - "arguments": { - "customer": "${ .customer }" - } - } - }, - "eventRef": "CreditCheckCompletedEvent", - "timeouts": { - "stateExecTimeout": "PT15M" - }, - "transition": "EvaluateDecision" - }, - { - "name": "EvaluateDecision", - "type": "switch", - "dataConditions": [ - { - "condition": "${ .creditCheck | .decision == \"Approved\" }", - "transition": "StartApplication" - }, - { - "condition": "${ .creditCheck | .decision == \"Denied\" }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "StartApplication", - "type": "operation", - "actions": [ - { - "subFlowRef": "startApplicationWorkflowId" - } - ], - "end": true - }, - { - "name": "RejectApplication", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/creditcheck.yml b/api/src/test/resources/examples/creditcheck.yml deleted file mode 100644 index 8831ada7..00000000 --- a/api/src/test/resources/examples/creditcheck.yml +++ /dev/null @@ -1,52 +0,0 @@ -id: customercreditcheck -version: '1.0' -specVersion: '0.8' -name: Customer Credit Check Workflow -description: Perform Customer Credit Check -start: CheckCredit -functions: - - name: creditCheckFunction - operation: http://myapis.org/creditcheckapi.json#doCreditCheck - - name: sendRejectionEmailFunction - operation: http://myapis.org/creditcheckapi.json#rejectionEmail -events: - - name: CreditCheckCompletedEvent - type: creditCheckCompleteType - source: creditCheckSource - correlation: - - contextAttributeName: customerId -states: - - name: CheckCredit - type: callback - action: - functionRef: - refName: callCreditCheckMicroservice - arguments: - customer: "${ .customer }" - eventRef: CreditCheckCompletedEvent - timeouts: - stateExecTimeout: PT15M - transition: EvaluateDecision - - name: EvaluateDecision - type: switch - dataConditions: - - condition: ${ .creditCheck | .decision == "Approved" } - transition: StartApplication - - condition: ${ .creditCheck | .decision == "Denied" } - transition: RejectApplication - defaultCondition: - transition: RejectApplication - - name: StartApplication - type: operation - actions: - - subFlowRef: startApplicationWorkflowId - end: true - - name: RejectApplication - type: operation - actionMode: sequential - actions: - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true diff --git a/api/src/test/resources/examples/eventbasedgreeting.json b/api/src/test/resources/examples/eventbasedgreeting.json deleted file mode 100644 index efdc2c92..00000000 --- a/api/src/test/resources/examples/eventbasedgreeting.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "id": "eventbasedgreeting", - "version": "1.0", - "specVersion": "0.8", - "name": "Event Based Greeting Workflow", - "description": "Event Based Greeting", - "start": "Greet", - "events": [ - { - "name": "GreetingEvent", - "type": "greetingEventType", - "source": "greetingEventSource" - } - ], - "functions": [ - { - "name": "greetingFunction", - "operation": "file://myapis/greetingapis.json#greeting" - } - ], - "states":[ - { - "name":"Greet", - "type":"event", - "onEvents": [{ - "eventRefs": ["GreetingEvent"], - "eventDataFilter": { - "data": "${ .data.greet }" - }, - "actions":[ - { - "functionRef": { - "refName": "greetingFunction", - "arguments": { - "name": "${ .greet.name }" - } - } - } - ] - }], - "stateDataFilter": { - "output": "${ .payload.greeting }" - }, - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/eventbasedgreeting.yml b/api/src/test/resources/examples/eventbasedgreeting.yml deleted file mode 100644 index c18b61fe..00000000 --- a/api/src/test/resources/examples/eventbasedgreeting.yml +++ /dev/null @@ -1,29 +0,0 @@ -id: eventbasedgreeting -version: '1.0' -specVersion: '0.8' -name: Event Based Greeting Workflow -description: Event Based Greeting -start: Greet -events: - - name: GreetingEvent - type: greetingEventType - source: greetingEventSource -functions: - - name: greetingFunction - operation: file://myapis/greetingapis.json#greeting -states: - - name: Greet - type: event - onEvents: - - eventRefs: - - GreetingEvent - eventDataFilter: - data: "${ .data.greet }" - actions: - - functionRef: - refName: greetingFunction - arguments: - name: "${ .greet.name }" - stateDataFilter: - output: "${ .payload.greeting }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/examples/eventbasedtransition.json b/api/src/test/resources/examples/eventbasedtransition.json deleted file mode 100644 index da0b8d6e..00000000 --- a/api/src/test/resources/examples/eventbasedtransition.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "id": "eventbasedswitch", - "version": "1.0", - "specVersion": "0.8", - "name": "Event Based Switch Transitions", - "description": "Event Based Switch Transitions", - "start": "CheckVisaStatus", - "events": [ - { - "name": "visaApprovedEvent", - "type": "VisaApproved", - "source": "visaCheckSource" - }, - { - "name": "visaRejectedEvent", - "type": "VisaRejected", - "source": "visaCheckSource" - } - ], - "states":[ - { - "name":"CheckVisaStatus", - "type":"switch", - "eventConditions": [ - { - "eventRef": "visaApprovedEvent", - "transition": "HandleApprovedVisa" - }, - { - "eventRef": "visaRejectedEvent", - "transition": "HandleRejectedVisa" - } - ], - "timeouts": { - "eventTimeout": "PT1H" - }, - "defaultCondition": { - "transition": "HandleNoVisaDecision" - } - }, - { - "name": "HandleApprovedVisa", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleApprovedVisaWorkflowID" - } - ], - "end": true - }, - { - "name": "HandleRejectedVisa", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleRejectedVisaWorkflowID" - } - ], - "end": true - }, - { - "name": "HandleNoVisaDecision", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleNoVisaDecisionWorkflowId" - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/eventbasedtransition.yml b/api/src/test/resources/examples/eventbasedtransition.yml deleted file mode 100644 index bb1203a1..00000000 --- a/api/src/test/resources/examples/eventbasedtransition.yml +++ /dev/null @@ -1,40 +0,0 @@ -id: eventbasedswitch -version: '1.0' -specVersion: '0.8' -name: Event Based Switch Transitions -description: Event Based Switch Transitions -start: CheckVisaStatus -events: - - name: visaApprovedEvent - type: VisaApproved - source: visaCheckSource - - name: visaRejectedEvent - type: VisaRejected - source: visaCheckSource -states: - - name: CheckVisaStatus - type: switch - eventConditions: - - eventRef: visaApprovedEvent - transition: HandleApprovedVisa - - eventRef: visaRejectedEvent - transition: HandleRejectedVisa - timeouts: - eventTimeout: PT1H - defaultCondition: - transition: HandleNoVisaDecision - - name: HandleApprovedVisa - type: operation - actions: - - subFlowRef: handleApprovedVisaWorkflowID - end: true - - name: HandleRejectedVisa - type: operation - actions: - - subFlowRef: handleRejectedVisaWorkflowID - end: true - - name: HandleNoVisaDecision - type: operation - actions: - - subFlowRef: handleNoVisaDecisionWorkflowId - end: true diff --git a/api/src/test/resources/examples/finalizecollegeapplication.json b/api/src/test/resources/examples/finalizecollegeapplication.json deleted file mode 100644 index 8fcb7670..00000000 --- a/api/src/test/resources/examples/finalizecollegeapplication.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "id": "finalizeCollegeApplication", - "name": "Finalize College Application", - "version": "1.0", - "specVersion": "0.8", - "start": "FinalizeApplication", - "events": [ - { - "name": "ApplicationSubmitted", - "type": "org.application.submitted", - "source": "applicationsource", - "correlation": [ - { - "contextAttributeName": "applicantId" - } - ] - }, - { - "name": "SATScoresReceived", - "type": "org.application.satscores", - "source": "applicationsource", - "correlation": [ - { - "contextAttributeName": "applicantId" - } - ] - }, - { - "name": "RecommendationLetterReceived", - "type": "org.application.recommendationLetter", - "source": "applicationsource", - "correlation": [ - { - "contextAttributeName": "applicantId" - } - ] - } - ], - "functions": [ - { - "name": "finalizeApplicationFunction", - "operation": "http://myapis.org/collegeapplicationapi.json#finalize" - } - ], - "states": [ - { - "name": "FinalizeApplication", - "type": "event", - "exclusive": false, - "onEvents": [ - { - "eventRefs": [ - "ApplicationSubmitted", - "SATScoresReceived", - "RecommendationLetterReceived" - ], - "actions": [ - { - "functionRef": { - "refName": "finalizeApplicationFunction", - "arguments": { - "student": "${ .applicantId }" - } - } - } - ] - } - ], - "end": { - "terminate": true - } - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/finalizecollegeapplication.yml b/api/src/test/resources/examples/finalizecollegeapplication.yml deleted file mode 100644 index 0d2fd30c..00000000 --- a/api/src/test/resources/examples/finalizecollegeapplication.yml +++ /dev/null @@ -1,40 +0,0 @@ -id: finalizeCollegeApplication -name: Finalize College Application -version: '1.0' -specVersion: '0.8' -start: FinalizeApplication -events: - - name: ApplicationSubmitted - type: org.application.submitted - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: SATScoresReceived - type: org.application.satscores - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: RecommendationLetterReceived - type: org.application.recommendationLetter - source: applicationsource - correlation: - - contextAttributeName: applicantId -functions: - - name: finalizeApplicationFunction - operation: http://myapis.org/collegeapplicationapi.json#finalize -states: - - name: FinalizeApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true \ No newline at end of file diff --git a/api/src/test/resources/examples/foreachstatewithactions.json b/api/src/test/resources/examples/foreachstatewithactions.json deleted file mode 100644 index e9953705..00000000 --- a/api/src/test/resources/examples/foreachstatewithactions.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "id": "foreachstatewithactions", - "name": "ForEach State With Actions", - "description": "ForEach State With Actions", - "version": "1.0", - "specVersion": "0.8", - "functions": [ - { - "name": "sendConfirmationFunction", - "operation": "http://myapis.org/confirmationapi.json#sendConfirmation" - } - ], - "states": [ - { - "name":"SendConfirmationForEachCompletedhOrder", - "type":"foreach", - "inputCollection": "${ .orders[?(@.completed == true)] }", - "iterationParam": "${ .completedorder }", - "actions":[ - { - "functionRef": { - "refName": "sendConfirmationFunction", - "arguments": { - "orderNumber": "${ .completedorder.orderNumber }", - "email": "${ .completedorder.email }" - } - } - }], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/foreachstatewithactions.yml b/api/src/test/resources/examples/foreachstatewithactions.yml deleted file mode 100644 index dfbcf4aa..00000000 --- a/api/src/test/resources/examples/foreachstatewithactions.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -id: foreachstatewithactions -name: ForEach State With Actions -description: ForEach State With Actions -version: '1.0' -specVersion: '0.8' -functions: - - name: sendConfirmationFunction - operation: http://myapis.org/confirmationapi.json#sendConfirmation -states: - - name: SendConfirmationForEachCompletedhOrder - type: foreach - inputCollection: "${ .orders[?(@.completed == true)] }" - iterationParam: "${ .completedorder }" - actions: - - functionRef: - refName: sendConfirmationFunction - arguments: - orderNumber: "${ .completedorder.orderNumber }" - email: "${ .completedorder.email }" - end: true diff --git a/api/src/test/resources/examples/greeting.json b/api/src/test/resources/examples/greeting.json deleted file mode 100644 index f9138d90..00000000 --- a/api/src/test/resources/examples/greeting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": "greeting", - "version": "1.0", - "specVersion": "0.8", - "name": "Greeting Workflow", - "description": "Greet Someone", - "start": "Greet", - "functions": [ - { - "name": "greetingFunction", - "operation": "file://myapis/greetingapis.json#greeting" - } - ], - "states":[ - { - "name":"Greet", - "type":"operation", - "actions":[ - { - "functionRef": { - "refName": "greetingFunction", - "arguments": { - "name": "${ .person.name }" - } - }, - "actionDataFilter": { - "results": "${ .greeting }" - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/greeting.yml b/api/src/test/resources/examples/greeting.yml deleted file mode 100644 index ceb14ae0..00000000 --- a/api/src/test/resources/examples/greeting.yml +++ /dev/null @@ -1,20 +0,0 @@ -id: greeting -version: '1.0' -specVersion: '0.8' -name: Greeting Workflow -description: Greet Someone -start: Greet -functions: - - name: greetingFunction - operation: file://myapis/greetingapis.json#greeting -states: - - name: Greet - type: operation - actions: - - functionRef: - refName: greetingFunction - arguments: - name: "${ .person.name }" - actionDataFilter: - results: "${ .greeting }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/examples/helloworld.json b/api/src/test/resources/examples/helloworld.json deleted file mode 100644 index c8d48ca8..00000000 --- a/api/src/test/resources/examples/helloworld.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "helloworld", - "version": "1.0", - "specVersion": "0.8", - "name": "Hello World Workflow", - "description": "Inject Hello World", - "start": "Hello State", - "states":[ - { - "name":"Hello State", - "type":"inject", - "data": { - "result": "Hello World!" - }, - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/helloworld.yml b/api/src/test/resources/examples/helloworld.yml deleted file mode 100644 index 32a84296..00000000 --- a/api/src/test/resources/examples/helloworld.yml +++ /dev/null @@ -1,12 +0,0 @@ -id: helloworld -version: '1.0' -specVersion: '0.8' -name: Hello World Workflow -description: Inject Hello World -start: Hello State -states: - - name: Hello State - type: inject - data: - result: Hello World! - end: true \ No newline at end of file diff --git a/api/src/test/resources/examples/jobmonitoring.json b/api/src/test/resources/examples/jobmonitoring.json deleted file mode 100644 index 8b0b8e9c..00000000 --- a/api/src/test/resources/examples/jobmonitoring.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "id": "jobmonitoring", - "version": "1.0", - "specVersion": "0.8", - "name": "Job Monitoring", - "description": "Monitor finished execution of a submitted job", - "start": "SubmitJob", - "functions": [ - { - "name": "submitJob", - "operation": "http://myapis.org/monitorapi.json#doSubmit" - }, - { - "name": "checkJobStatus", - "operation": "http://myapis.org/monitorapi.json#checkStatus" - }, - { - "name": "reportJobSuceeded", - "operation": "http://myapis.org/monitorapi.json#reportSucceeded" - }, - { - "name": "reportJobFailed", - "operation": "http://myapis.org/monitorapi.json#reportFailure" - } - ], - "states":[ - { - "name":"SubmitJob", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "submitJob", - "arguments": { - "name": "${ .job.name }" - } - }, - "actionDataFilter": { - "results": "${ .jobuid }" - } - } - ], - "onErrors": [ - { - "errorRef": "AllErrors", - "transition": "SubmitError" - } - ], - "stateDataFilter": { - "output": "${ .jobuid }" - }, - "transition": "WaitForCompletion" - }, - { - "name": "SubmitError", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleJobSubmissionErrorWorkflow" - } - ], - "end": true - }, - { - "name": "WaitForCompletion", - "type": "sleep", - "duration": "PT5S", - "transition": "GetJobStatus" - }, - { - "name":"GetJobStatus", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "checkJobStatus", - "arguments": { - "name": "${ .jobuid }" - } - }, - "actionDataFilter": { - "results": "${ .jobstatus }" - } - } - ], - "stateDataFilter": { - "output": "${ .jobstatus }" - }, - "transition": "DetermineCompletion" - }, - { - "name":"DetermineCompletion", - "type":"switch", - "dataConditions": [ - { - "condition": "${ .jobStatus == \"SUCCEEDED\" }", - "transition": "JobSucceeded" - }, - { - "condition": "${ .jobStatus == \"FAILED\" }", - "transition": "JobFailed" - } - ], - "defaultCondition": { - "transition": "WaitForCompletion" - } - }, - { - "name":"JobSucceeded", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "reportJobSuceeded", - "arguments": { - "name": "${ .jobuid }" - } - } - } - ], - "end": true - }, - { - "name":"JobFailed", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "reportJobFailed", - "arguments": { - "name": "${ .jobuid }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/jobmonitoring.yml b/api/src/test/resources/examples/jobmonitoring.yml deleted file mode 100644 index eab235d5..00000000 --- a/api/src/test/resources/examples/jobmonitoring.yml +++ /dev/null @@ -1,81 +0,0 @@ -id: jobmonitoring -version: '1.0' -specVersion: '0.8' -name: Job Monitoring -description: Monitor finished execution of a submitted job -start: SubmitJob -functions: - - name: submitJob - operation: http://myapis.org/monitorapi.json#doSubmit - - name: checkJobStatus - operation: http://myapis.org/monitorapi.json#checkStatus - - name: reportJobSuceeded - operation: http://myapis.org/monitorapi.json#reportSucceeded - - name: reportJobFailed - operation: http://myapis.org/monitorapi.json#reportFailure -states: - - name: SubmitJob - type: operation - actionMode: sequential - actions: - - functionRef: - refName: submitJob - arguments: - name: "${ .job.name }" - actionDataFilter: - results: "${ .jobuid }" - onErrors: - - errorRef: "AllErrors" - transition: SubmitError - stateDataFilter: - output: "${ .jobuid }" - transition: WaitForCompletion - - name: SubmitError - type: operation - actions: - - subFlowRef: handleJobSubmissionErrorWorkflow - end: true - - name: WaitForCompletion - type: sleep - duration: PT5S - transition: GetJobStatus - - name: GetJobStatus - type: operation - actionMode: sequential - actions: - - functionRef: - refName: checkJobStatus - arguments: - name: "${ .jobuid }" - actionDataFilter: - results: "${ .jobstatus }" - stateDataFilter: - output: "${ .jobstatus }" - transition: DetermineCompletion - - name: DetermineCompletion - type: switch - dataConditions: - - condition: ${ .jobStatus == "SUCCEEDED" } - transition: JobSucceeded - - condition: ${ .jobStatus == "FAILED" } - transition: JobFailed - defaultCondition: - transition: WaitForCompletion - - name: JobSucceeded - type: operation - actionMode: sequential - actions: - - functionRef: - refName: reportJobSuceeded - arguments: - name: "${ .jobuid }" - end: true - - name: JobFailed - type: operation - actionMode: sequential - actions: - - functionRef: - refName: reportJobFailed - arguments: - name: "${ .jobuid }" - end: true diff --git a/api/src/test/resources/examples/monitorpatient.json b/api/src/test/resources/examples/monitorpatient.json deleted file mode 100644 index 594bf18c..00000000 --- a/api/src/test/resources/examples/monitorpatient.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "id": "patientVitalsWorkflow", - "name": "Monitor Patient Vitals", - "version": "1.0", - "specVersion": "0.8", - "start": "MonitorVitals", - "events": [ - { - "name": "HighBodyTemperature", - "type": "org.monitor.highBodyTemp", - "source": "monitoringSource", - "correlation": [ - { - "contextAttributeName": "patientId" - } - ] - }, - { - "name": "HighBloodPressure", - "type": "org.monitor.highBloodPressure", - "source": "monitoringSource", - "correlation": [ - { - "contextAttributeName": "patientId" - } - ] - }, - { - "name": "HighRespirationRate", - "type": "org.monitor.highRespirationRate", - "source": "monitoringSource", - "correlation": [ - { - "contextAttributeName": "patientId" - } - ] - } - ], - "functions": [ - { - "name": "callPulmonologist", - "operation": "http://myapis.org/patientapis.json#callPulmonologist" - }, - { - "name": "sendTylenolOrder", - "operation": "http://myapis.org/patientapis.json#tylenolOrder" - }, - { - "name": "callNurse", - "operation": "http://myapis.org/patientapis.json#callNurse" - } - ], - "states": [ - { - "name": "MonitorVitals", - "type": "event", - "exclusive": true, - "onEvents": [{ - "eventRefs": ["HighBodyTemperature"], - "actions": [{ - "functionRef": { - "refName": "sendTylenolOrder", - "arguments": { - "patientid": "${ .patientId }" - } - } - }] - }, - { - "eventRefs": ["HighBloodPressure"], - "actions": [{ - "functionRef": { - "refName": "callNurse", - "arguments": { - "patientid": "${ .patientId }" - } - } - }] - }, - { - "eventRefs": ["HighRespirationRate"], - "actions": [{ - "functionRef": { - "refName": "callPulmonologist", - "arguments": { - "patientid": "${ .patientId }" - } - } - }] - } - ], - "end": { - "terminate": true - } - }] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/monitorpatient.yml b/api/src/test/resources/examples/monitorpatient.yml deleted file mode 100644 index 034bc0ec..00000000 --- a/api/src/test/resources/examples/monitorpatient.yml +++ /dev/null @@ -1,56 +0,0 @@ -id: patientVitalsWorkflow -name: Monitor Patient Vitals -version: '1.0' -specVersion: '0.8' -start: Monitor Vitals -events: - - name: HighBodyTemperature - type: org.monitor.highBodyTemp - source: monitoringSource - correlation: - - contextAttributeName: patientId - - name: HighBloodPressure - type: org.monitor.highBloodPressure - source: monitoringSource - correlation: - - contextAttributeName: patientId - - name: HighRespirationRate - type: org.monitor.highRespirationRate - source: monitoringSource - correlation: - - contextAttributeName: patientId -functions: - - name: callPulmonologist - operation: http://myapis.org/patientapis.json#callPulmonologist - - name: sendTylenolOrder - operation: http://myapis.org/patientapis.json#tylenolOrder - - name: callNurse - operation: http://myapis.org/patientapis.json#callNurse -states: - - name: MonitorVitals - type: event - exclusive: true - onEvents: - - eventRefs: - - HighBodyTemperature - actions: - - functionRef: - refName: sendTylenolOrder - arguments: - patientid: "${ .patientId }" - - eventRefs: - - HighBloodPressure - actions: - - functionRef: - refName: callNurse - arguments: - patientid: "${ .patientId }" - - eventRefs: - - HighRespirationRate - actions: - - functionRef: - refName: callPulmonologist - arguments: - patientid: "${ .patientId }" - end: - terminate: true \ No newline at end of file diff --git a/api/src/test/resources/examples/parallel.json b/api/src/test/resources/examples/parallel.json deleted file mode 100644 index 1d614f50..00000000 --- a/api/src/test/resources/examples/parallel.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "id": "parallelexec", - "version": "1.0", - "specVersion": "0.8", - "name": "Parallel Execution Workflow", - "description": "Executes two branches in parallel", - "start": "ParallelExec", - "states":[ - { - "name": "ParallelExec", - "type": "parallel", - "completionType": "allOf", - "branches": [ - { - "name": "ShortDelayBranch" - }, - { - "name": "LongDelayBranch" - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/parallel.yml b/api/src/test/resources/examples/parallel.yml deleted file mode 100644 index 5a586cdf..00000000 --- a/api/src/test/resources/examples/parallel.yml +++ /dev/null @@ -1,14 +0,0 @@ -id: parallelexec -version: '1.0' -specVersion: '0.8' -name: Parallel Execution Workflow -description: Executes two branches in parallel -start: ParallelExec -states: - - name: ParallelExec - type: parallel - completionType: allOf - branches: - - name: ShortDelayBranch - - name: LongDelayBranch - end: true \ No newline at end of file diff --git a/api/src/test/resources/examples/periodicinboxcheck.json b/api/src/test/resources/examples/periodicinboxcheck.json deleted file mode 100644 index 6c1ecc96..00000000 --- a/api/src/test/resources/examples/periodicinboxcheck.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "id": "checkInbox", - "name": "Check Inbox Workflow", - "description": "Periodically Check Inbox", - "start": { - "stateName": "CheckInbox", - "schedule": { - "cron": "0 0/15 * * * ?" - } - }, - "version": "1.0", - "specVersion": "0.8", - "functions": [ - { - "name": "checkInboxFunction", - "operation": "http://myapis.org/inboxapi.json#checkNewMessages" - }, - { - "name": "sendTextFunction", - "operation": "http://myapis.org/inboxapi.json#sendText" - } - ], - "states": [ - { - "name": "CheckInbox", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "checkInboxFunction" - } - ], - "transition": "SendTextForHighPriority" - }, - { - "name": "SendTextForHighPriority", - "type": "foreach", - "inputCollection": "${ .messages }", - "iterationParam": "singlemessage", - "actions": [ - { - "functionRef": { - "refName": "sendTextFunction", - "arguments": { - "message": "${ .singlemessage }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/periodicinboxcheck.yml b/api/src/test/resources/examples/periodicinboxcheck.yml deleted file mode 100644 index d04932e6..00000000 --- a/api/src/test/resources/examples/periodicinboxcheck.yml +++ /dev/null @@ -1,31 +0,0 @@ -id: checkInbox -name: Check Inbox Workflow -description: Periodically Check Inbox -start: - stateName: CheckInbox - schedule: - cron: 0 0/15 * * * ? -version: '1.0' -specVersion: '0.8' -functions: - - name: checkInboxFunction - operation: http://myapis.org/inboxapi.json#checkNewMessages - - name: sendTextFunction - operation: http://myapis.org/inboxapi.json#sendText -states: - - name: CheckInbox - type: operation - actionMode: sequential - actions: - - functionRef: checkInboxFunction - transition: SendTextForHighPriority - - name: SendTextForHighPriority - type: foreach - inputCollection: "${ .messages }" - iterationParam: singlemessage - actions: - - functionRef: - refName: sendTextFunction - arguments: - message: "${ .singlemessage }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/examples/provisionorder.json b/api/src/test/resources/examples/provisionorder.json deleted file mode 100644 index 57d3b33a..00000000 --- a/api/src/test/resources/examples/provisionorder.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "id": "provisionorders", - "version": "1.0", - "specVersion": "0.8", - "name": "Provision Orders", - "description": "Provision Orders and handle errors thrown", - "start": "ProvisionOrder", - "functions": [ - { - "name": "provisionOrderFunction", - "operation": "http://myapis.org/provisioningapi.json#doProvision" - } - ], - "states":[ - { - "name":"ProvisionOrder", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "provisionOrderFunction", - "arguments": { - "order": "${ .order }" - } - } - } - ], - "stateDataFilter": { - "output": "${ .exceptions }" - }, - "transition": "ApplyOrder", - "onErrors": [ - { - "errorRef": "Missing order id", - "transition": "MissingId" - }, - { - "errorRef": "Missing order item", - "transition": "MissingItem" - }, - { - "errorRef": "Missing order quantity", - "transition": "MissingQuantity" - } - ] - }, - { - "name": "MissingId", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleMissingIdExceptionWorkflow" - } - ], - "end": true - }, - { - "name": "MissingItem", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleMissingItemExceptionWorkflow" - } - ], - "end": true - }, - { - "name": "MissingQuantity", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleMissingQuantityExceptionWorkflow" - } - ], - "end": true - }, - { - "name": "ApplyOrder", - "type": "operation", - "actions": [ - { - "subFlowRef": "applyOrderWorkflowId" - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/provisionorder.yml b/api/src/test/resources/examples/provisionorder.yml deleted file mode 100644 index 7233e5c3..00000000 --- a/api/src/test/resources/examples/provisionorder.yml +++ /dev/null @@ -1,48 +0,0 @@ -id: provisionorders -version: '1.0' -specVersion: '0.8' -name: Provision Orders -description: Provision Orders and handle errors thrown -start: ProvisionOrder -functions: - - name: provisionOrderFunction - operation: http://myapis.org/provisioningapi.json#doProvision -states: - - name: ProvisionOrder - type: operation - actionMode: sequential - actions: - - functionRef: - refName: provisionOrderFunction - arguments: - order: "${ .order }" - stateDataFilter: - output: "${ .exceptions }" - transition: ApplyOrder - onErrors: - - errorRef: Missing order id - transition: MissingId - - errorRef: Missing order item - transition: MissingItem - - errorRef: Missing order quantity - transition: MissingQuantity - - name: MissingId - type: operation - actions: - - subFlowRef: handleMissingIdExceptionWorkflow - end: true - - name: MissingItem - type: operation - actions: - - subFlowRef: handleMissingItemExceptionWorkflow - end: true - - name: MissingQuantity - type: operation - actions: - - subFlowRef: handleMissingQuantityExceptionWorkflow - end: true - - name: ApplyOrder - type: operation - actions: - - subFlowRef: applyOrderWorkflowId - end: true diff --git a/api/src/test/resources/examples/roomreadings.json b/api/src/test/resources/examples/roomreadings.json deleted file mode 100644 index 14f58b9b..00000000 --- a/api/src/test/resources/examples/roomreadings.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "id": "roomreadings", - "name": "Room Temp and Humidity Workflow", - "version": "1.0", - "specVersion": "0.8", - "start": "ConsumeReading", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1H", - "runBefore": "GenerateReport" - } - }, - "keepActive": true, - "states": [ - { - "name": "ConsumeReading", - "type": "event", - "onEvents": [ - { - "eventRefs": ["TemperatureEvent", "HumidityEvent"], - "actions": [ - { - "functionRef": { - "refName": "LogReading" - } - } - ], - "eventDataFilter": { - "data": "${ .readings }" - } - } - ], - "end": true - }, - { - "name": "GenerateReport", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "ProduceReport", - "arguments": { - "data": "${ .readings }" - } - } - } - ], - "end": { - "terminate": true - } - } - ], - "events": [ - { - "name": "TemperatureEvent", - "type": "my.home.sensors", - "source": "/home/rooms/+", - "correlation": [ - { - "contextAttributeName": "roomId" - } - ] - }, - { - "name": "HumidityEvent", - "type": "my.home.sensors", - "source": "/home/rooms/+", - "correlation": [ - { - "contextAttributeName": "roomId" - } - ] - } - ], - "functions": [ - { - "name": "LogReading", - "operation": "http.myorg.io/ordersservices.json#logreading" - }, - { - "name": "ProduceReport", - "operation": "http.myorg.io/ordersservices.json#produceReport" - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/roomreadings.yml b/api/src/test/resources/examples/roomreadings.yml deleted file mode 100644 index 948de4a0..00000000 --- a/api/src/test/resources/examples/roomreadings.yml +++ /dev/null @@ -1,48 +0,0 @@ -id: roomreadings -name: Room Temp and Humidity Workflow -version: '1.0' -specVersion: '0.8' -start: ConsumeReading -timeouts: - workflowExecTimeout: - duration: PT1H - runBefore: GenerateReport -keepActive: true -states: - - name: ConsumeReading - type: event - onEvents: - - eventRefs: - - TemperatureEvent - - HumidityEvent - actions: - - functionRef: - refName: LogReading - eventDataFilter: - data: "${ .readings }" - end: true - - name: GenerateReport - type: operation - actions: - - functionRef: - refName: ProduceReport - arguments: - data: "${ .readings }" - end: - terminate: true -events: - - name: TemperatureEvent - type: my.home.sensors - source: "/home/rooms/+" - correlation: - - contextAttributeName: roomId - - name: HumidityEvent - type: my.home.sensors - source: "/home/rooms/+" - correlation: - - contextAttributeName: roomId -functions: - - name: LogReading - operation: http.myorg.io/ordersservices.json#logreading - - name: ProduceReport - operation: http.myorg.io/ordersservices.json#produceReport diff --git a/api/src/test/resources/examples/sendcloudevent.json b/api/src/test/resources/examples/sendcloudevent.json deleted file mode 100644 index 14cd9cad..00000000 --- a/api/src/test/resources/examples/sendcloudevent.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "id": "sendcloudeventonprovision", - "version": "1.0", - "specVersion": "0.8", - "name": "Send CloudEvent on provision completion", - "start": "ProvisionOrdersState", - "events": [ - { - "name": "provisioningCompleteEvent", - "type": "provisionCompleteType", - "kind": "produced" - } - ], - "functions": [ - { - "name": "provisionOrderFunction", - "operation": "http://myapis.org/provisioning.json#doProvision" - } - ], - "states": [ - { - "name": "ProvisionOrdersState", - "type": "foreach", - "inputCollection": "${ .orders }", - "iterationParam": "singleorder", - "outputCollection": "${ .provisionedOrders }", - "actions": [ - { - "functionRef": { - "refName": "provisionOrderFunction", - "arguments": { - "order": "${ .singleorder }" - } - } - } - ], - "end": { - "produceEvents": [{ - "eventRef": "provisioningCompleteEvent", - "data": "${ .provisionedOrders }" - }] - } - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/sendcloudevent.yml b/api/src/test/resources/examples/sendcloudevent.yml deleted file mode 100644 index 037b0648..00000000 --- a/api/src/test/resources/examples/sendcloudevent.yml +++ /dev/null @@ -1,27 +0,0 @@ -id: sendcloudeventonprovision -version: '1.0' -specVersion: '0.8' -name: Send CloudEvent on provision completion -start: ProvisionOrdersState -events: - - name: provisioningCompleteEvent - type: provisionCompleteType - kind: produced -functions: - - name: provisionOrderFunction - operation: http://myapis.org/provisioning.json#doProvision -states: - - name: ProvisionOrdersState - type: foreach - inputCollection: "${ .orders }" - iterationParam: singleorder - outputCollection: "${ .provisionedOrders }" - actions: - - functionRef: - refName: provisionOrderFunction - arguments: - order: "${ .singleorder }" - end: - produceEvents: - - eventRef: provisioningCompleteEvent - data: "${ .provisionedOrders }" \ No newline at end of file diff --git a/api/src/test/resources/examples/solvemathproblems.json b/api/src/test/resources/examples/solvemathproblems.json deleted file mode 100644 index 29c9de38..00000000 --- a/api/src/test/resources/examples/solvemathproblems.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "id": "solvemathproblems", - "version": "1.0", - "specVersion": "0.8", - "name": "Solve Math Problems Workflow", - "description": "Solve math problems", - "start": "Solve", - "functions": [ - { - "name": "solveMathExpressionFunction", - "operation": "http://myapis.org/mapthapis.json#solveExpression" - } - ], - "states":[ - { - "name":"Solve", - "type":"foreach", - "inputCollection": "${ .expressions }", - "iterationParam": "singleexpression", - "outputCollection": "${ .results }", - "actions":[ - { - "functionRef": { - "refName": "solveMathExpressionFunction", - "arguments": { - "expression": "${ .singleexpression }" - } - } - } - ], - "stateDataFilter": { - "output": "${ .results }" - }, - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/solvemathproblems.yml b/api/src/test/resources/examples/solvemathproblems.yml deleted file mode 100644 index 883c3e1b..00000000 --- a/api/src/test/resources/examples/solvemathproblems.yml +++ /dev/null @@ -1,23 +0,0 @@ -id: solvemathproblems -version: '1.0' -specVersion: '0.8' -name: Solve Math Problems Workflow -description: Solve math problems -start: Solve -functions: - - name: solveMathExpressionFunction - operation: http://myapis.org/mapthapis.json#solveExpression -states: - - name: Solve - type: foreach - inputCollection: "${ .expressions }" - iterationParam: singleexpression - outputCollection: "${ .results }" - actions: - - functionRef: - refName: solveMathExpressionFunction - arguments: - expression: "${ .singleexpression }" - stateDataFilter: - output: "${ .results }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/examples/vetappointmentservice.json b/api/src/test/resources/examples/vetappointmentservice.json deleted file mode 100644 index 92db914e..00000000 --- a/api/src/test/resources/examples/vetappointmentservice.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "id": "VetAppointmentWorkflow", - "name": "Vet Appointment Workflow", - "description": "Vet service call via events", - "version": "1.0", - "specVersion": "0.8", - "start": "MakeVetAppointmentState", - "events": [ - { - "name": "MakeVetAppointment", - "source": "VetServiceSoure", - "kind": "produced" - }, - { - "name": "VetAppointmentInfo", - "source": "VetServiceSource", - "kind": "consumed" - } - ], - "states": [ - { - "name": "MakeVetAppointmentState", - "type": "operation", - "actions": [ - { - "name": "MakeAppointmentAction", - "eventRef": { - "triggerEventRef": "MakeVetAppointment", - "data": "${ .patientInfo }", - "resultEventRef": "VetAppointmentInfo" - }, - "actionDataFilter": { - "results": "${ .appointmentInfo }" - } - } - ], - "timeouts": { - "actionExecTimeout": "PT15M" - }, - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/examples/vetappointmentservice.yml b/api/src/test/resources/examples/vetappointmentservice.yml deleted file mode 100644 index d102f32b..00000000 --- a/api/src/test/resources/examples/vetappointmentservice.yml +++ /dev/null @@ -1,27 +0,0 @@ -id: VetAppointmentWorkflow -name: Vet Appointment Workflow -description: Vet service call via events -version: '1.0' -specVersion: '0.8' -start: MakeVetAppointmentState -events: - - name: MakeVetAppointment - source: VetServiceSoure - kind: produced - - name: VetAppointmentInfo - source: VetServiceSource - kind: consumed -states: - - name: MakeVetAppointmentState - type: operation - actions: - - name: MakeAppointmentAction - eventRef: - triggerEventRef: MakeVetAppointment - data: "${ .patientInfo }" - resultEventRef: VetAppointmentInfo - actionDataFilter: - results: "${ .appointmentInfo }" - timeouts: - actionExecTimeout: PT15M - end: true diff --git a/api/src/test/resources/features/actionssleep.json b/api/src/test/resources/features/actionssleep.json deleted file mode 100644 index 8f422ef5..00000000 --- a/api/src/test/resources/features/actionssleep.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "id": "functionrefs", - "version": "1.0", - "specVersion": "0.8", - "name": "Customer Credit Check Workflow", - "description": "Perform Customer Credit Check", - "start": "TestFunctionRef", - "functions": [ - { - "name": "creditCheckFunction", - "operation": "http://myapis.org/creditcheckapi.json#doCreditCheck" - }, - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/creditcheckapi.json#rejectionEmail" - } - ], - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction", - "sleep": { - "before": "PT5S", - "after": "PT10S" - } - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - }, - "sleep": { - "before": "PT5S", - "after": "PT10S" - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/actionssleep.yml b/api/src/test/resources/features/actionssleep.yml deleted file mode 100644 index 9bfbe9a7..00000000 --- a/api/src/test/resources/features/actionssleep.yml +++ /dev/null @@ -1,28 +0,0 @@ -id: functionrefs -version: '1.0' -specVersion: '0.8' -name: Customer Credit Check Workflow -description: Perform Customer Credit Check -start: TestFunctionRef -functions: - - name: creditCheckFunction - operation: http://myapis.org/creditcheckapi.json#doCreditCheck - - name: sendRejectionEmailFunction - operation: http://myapis.org/creditcheckapi.json#rejectionEmail -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - sleep: - before: PT5S - after: PT10S - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - sleep: - before: PT5S - after: PT10S - end: true diff --git a/api/src/test/resources/features/annotations.json b/api/src/test/resources/features/annotations.json deleted file mode 100644 index 90ed6dd1..00000000 --- a/api/src/test/resources/features/annotations.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id" : "test-workflow", - "name" : "test-workflow-name", - "version" : "1.0", - "annotations": ["a", "b", "c", "d"] -} \ No newline at end of file diff --git a/api/src/test/resources/features/annotations.yml b/api/src/test/resources/features/annotations.yml deleted file mode 100644 index 54e359ae..00000000 --- a/api/src/test/resources/features/annotations.yml +++ /dev/null @@ -1,8 +0,0 @@ -id: test-workflow -name: test-workflow-name -version: '1.0' -annotations: - - a - - b - - c - - d diff --git a/api/src/test/resources/features/applicantrequest-with-id-and-key.json b/api/src/test/resources/features/applicantrequest-with-id-and-key.json deleted file mode 100644 index 405d7c36..00000000 --- a/api/src/test/resources/features/applicantrequest-with-id-and-key.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "id": "applicant-with-key-and-id", - "key": "applicant-key-request", - "version": "1.0", - "specVersion": "0.8", - "name": "Applicant Request Decision Workflow", - "description": "Determine if applicant request is valid", - "start": "CheckApplication", - "functions": [ - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/applicationapi.json#emailRejection" - } - ], - "states":[ - { - "name":"CheckApplication", - "type":"switch", - "dataConditions": [ - { - "condition": "${ .applicants | .age >= 18 }", - "transition": "StartApplication" - }, - { - "condition": "${ .applicants | .age < 18 }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "StartApplication", - "type": "operation", - "actions": [ - { - "subFlowRef": "startApplicationWorkflowId" - } - ], - "end": true - }, - { - "name":"RejectApplication", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .applicant }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/applicantrequest-with-id-and-key.yml b/api/src/test/resources/features/applicantrequest-with-id-and-key.yml deleted file mode 100644 index 8a123663..00000000 --- a/api/src/test/resources/features/applicantrequest-with-id-and-key.yml +++ /dev/null @@ -1,34 +0,0 @@ -id: applicant-with-key-and-id -key: applicant-key-request -version: '1.0' -specVersion: '0.8' -name: Applicant Request Decision Workflow -description: Determine if applicant request is valid -start: CheckApplication -functions: - - name: sendRejectionEmailFunction - operation: http://myapis.org/applicationapi.json#emailRejection -states: - - name: CheckApplication - type: switch - dataConditions: - - condition: "${ .applicants | .age >= 18 }" - transition: StartApplication - - condition: "${ .applicants | .age < 18 }" - transition: RejectApplication - defaultCondition: - transition: RejectApplication - - name: StartApplication - type: operation - actions: - - subFlowRef: startApplicationWorkflowId - end: true - - name: RejectApplication - type: operation - actionMode: sequential - actions: - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .applicant }" - end: true diff --git a/api/src/test/resources/features/applicantrequest-with-key.json b/api/src/test/resources/features/applicantrequest-with-key.json deleted file mode 100644 index f0481b00..00000000 --- a/api/src/test/resources/features/applicantrequest-with-key.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "key": "applicant-key-request", - "version": "1.0", - "specVersion": "0.8", - "name": "Applicant Request Decision Workflow", - "description": "Determine if applicant request is valid", - "start": "CheckApplication", - "functions": [ - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/applicationapi.json#emailRejection" - } - ], - "states":[ - { - "name":"CheckApplication", - "type":"switch", - "dataConditions": [ - { - "condition": "${ .applicants | .age >= 18 }", - "transition": "StartApplication" - }, - { - "condition": "${ .applicants | .age < 18 }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "StartApplication", - "type": "operation", - "actions": [ - { - "subFlowRef": "startApplicationWorkflowId" - } - ], - "end": true - }, - { - "name":"RejectApplication", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .applicant }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/applicantrequest-with-key.yml b/api/src/test/resources/features/applicantrequest-with-key.yml deleted file mode 100644 index 85beed74..00000000 --- a/api/src/test/resources/features/applicantrequest-with-key.yml +++ /dev/null @@ -1,33 +0,0 @@ -key: applicant-key-request -version: '1.0' -specVersion: '0.8' -name: Applicant Request Decision Workflow -description: Determine if applicant request is valid -start: CheckApplication -functions: - - name: sendRejectionEmailFunction - operation: http://myapis.org/applicationapi.json#emailRejection -states: - - name: CheckApplication - type: switch - dataConditions: - - condition: "${ .applicants | .age >= 18 }" - transition: StartApplication - - condition: "${ .applicants | .age < 18 }" - transition: RejectApplication - defaultCondition: - transition: RejectApplication - - name: StartApplication - type: operation - actions: - - subFlowRef: startApplicationWorkflowId - end: true - - name: RejectApplication - type: operation - actionMode: sequential - actions: - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .applicant }" - end: true diff --git a/api/src/test/resources/features/applicantrequest.json b/api/src/test/resources/features/applicantrequest.json deleted file mode 100644 index 1621c2bd..00000000 --- a/api/src/test/resources/features/applicantrequest.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "id": "applicantrequest", - "version": "1.0", - "specVersion": "0.8", - "name": "Applicant Request Decision Workflow", - "description": "Determine if applicant request is valid", - "start": "CheckApplication", - "functions": [ - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/applicationapi.json#emailRejection" - } - ], - "states":[ - { - "name":"CheckApplication", - "type":"switch", - "dataConditions": [ - { - "condition": "${ .applicants | .age >= 18 }", - "transition": "StartApplication" - }, - { - "condition": "${ .applicants | .age < 18 }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "StartApplication", - "type": "operation", - "actions": [ - { - "subFlowRef": "startApplicationWorkflowId" - } - ], - "end": true - }, - { - "name":"RejectApplication", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .applicant }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/applicantrequest.yml b/api/src/test/resources/features/applicantrequest.yml deleted file mode 100644 index ae0db1be..00000000 --- a/api/src/test/resources/features/applicantrequest.yml +++ /dev/null @@ -1,33 +0,0 @@ -id: applicantrequest -version: '1.0' -specVersion: '0.8' -name: Applicant Request Decision Workflow -description: Determine if applicant request is valid -start: CheckApplication -functions: - - name: sendRejectionEmailFunction - operation: http://myapis.org/applicationapi.json#emailRejection -states: - - name: CheckApplication - type: switch - dataConditions: - - condition: "${ .applicants | .age >= 18 }" - transition: StartApplication - - condition: "${ .applicants | .age < 18 }" - transition: RejectApplication - defaultCondition: - transition: RejectApplication - - name: StartApplication - type: operation - actions: - - subFlowRef: startApplicationWorkflowId - end: true - - name: RejectApplication - type: operation - actionMode: sequential - actions: - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .applicant }" - end: true diff --git a/api/src/test/resources/features/applicantrequestfunctions.json b/api/src/test/resources/features/applicantrequestfunctions.json deleted file mode 100644 index bafc861b..00000000 --- a/api/src/test/resources/features/applicantrequestfunctions.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "functions": [ - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/application.json#emailRejection" - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/applicantrequestfunctions.yml b/api/src/test/resources/features/applicantrequestfunctions.yml deleted file mode 100644 index a1e90f93..00000000 --- a/api/src/test/resources/features/applicantrequestfunctions.yml +++ /dev/null @@ -1,3 +0,0 @@ -functions: - - name: sendRejectionEmailFunction - operation: http://myapis.org/application.json#emailRejection diff --git a/api/src/test/resources/features/applicantrequestretries.json b/api/src/test/resources/features/applicantrequestretries.json deleted file mode 100644 index 40f83b55..00000000 --- a/api/src/test/resources/features/applicantrequestretries.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "retries": [ - { - "name": "TimeoutRetryStrategy", - "delay": "PT1M", - "maxAttempts": "5" - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/applicantrequestretries.yml b/api/src/test/resources/features/applicantrequestretries.yml deleted file mode 100644 index fa4c810d..00000000 --- a/api/src/test/resources/features/applicantrequestretries.yml +++ /dev/null @@ -1,4 +0,0 @@ -retries: - - name: TimeoutRetryStrategy - delay: PT1M - maxAttempts: '5' diff --git a/api/src/test/resources/features/authbasic.json b/api/src/test/resources/features/authbasic.json deleted file mode 100644 index 31e86599..00000000 --- a/api/src/test/resources/features/authbasic.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "id": "test-workflow", - "name": "test-workflow-name", - "version": "1.0", - "auth": [ - { - "name": "authname", - "scheme": "basic", - "properties": { - "username": "testuser", - "password": "testpassword" - } - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/authbasic.yml b/api/src/test/resources/features/authbasic.yml deleted file mode 100644 index e04d1f7e..00000000 --- a/api/src/test/resources/features/authbasic.yml +++ /dev/null @@ -1,9 +0,0 @@ -id: test-workflow -name: test-workflow-name -version: '1.0' -auth: - - name: authname - scheme: basic - properties: - username: testuser - password: testpassword diff --git a/api/src/test/resources/features/authbearer.json b/api/src/test/resources/features/authbearer.json deleted file mode 100644 index be7c037a..00000000 --- a/api/src/test/resources/features/authbearer.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "test-workflow", - "name": "test-workflow-name", - "version": "1.0", - "auth": [ - { - "name": "authname", - "scheme": "bearer", - "properties": { - "token": "testtoken" - } - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/authbearer.yml b/api/src/test/resources/features/authbearer.yml deleted file mode 100644 index 292fa3c2..00000000 --- a/api/src/test/resources/features/authbearer.yml +++ /dev/null @@ -1,8 +0,0 @@ -id: test-workflow -name: test-workflow-name -version: '1.0' -auth: - - name: authname - scheme: bearer - properties: - token: testtoken diff --git a/api/src/test/resources/features/authoauth.json b/api/src/test/resources/features/authoauth.json deleted file mode 100644 index 10b76d70..00000000 --- a/api/src/test/resources/features/authoauth.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "id" : "test-workflow", - "name" : "test-workflow-name", - "version" : "1.0", - "auth" : [{ - "name" : "authname", - "scheme" : "oauth2", - "properties" : { - "authority" : "testauthority", - "grantType" : "clientCredentials", - "clientId": "${ $SECRETS.clientid }", - "clientSecret": "${ $SECRETS.clientsecret }" - } - }] -} \ No newline at end of file diff --git a/api/src/test/resources/features/authoauth.yml b/api/src/test/resources/features/authoauth.yml deleted file mode 100644 index cb2c52ba..00000000 --- a/api/src/test/resources/features/authoauth.yml +++ /dev/null @@ -1,11 +0,0 @@ -id: test-workflow -name: test-workflow-name -version: '1.0' -auth: - - name: authname - scheme: oauth2 - properties: - authority: testauthority - grantType: clientCredentials - clientId: "${ $SECRETS.clientid }" - clientSecret: "${ $SECRETS.clientsecret }" diff --git a/api/src/test/resources/features/callHttp.yaml b/api/src/test/resources/features/callHttp.yaml new file mode 100644 index 00000000..b7f8457d --- /dev/null +++ b/api/src/test/resources/features/callHttp.yaml @@ -0,0 +1,13 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: http-call-with-content-output +do: + getFirstAvailablePet: + call: http + with: + method: get + endpoint: + uri: https://petstore.swagger.io/v2/pet/findByStatus?status={status} + output: + from: .[0] diff --git a/api/src/test/resources/features/callOpenAPI.yaml b/api/src/test/resources/features/callOpenAPI.yaml new file mode 100644 index 00000000..fef1ae95 --- /dev/null +++ b/api/src/test/resources/features/callOpenAPI.yaml @@ -0,0 +1,15 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: openapi-call-with-content-output +do: + getPetsByStatus: + call: openapi + with: + document: + uri: https://petstore.swagger.io/v2/swagger.json + operation: findPetsByStatus + parameters: + status: ${ .status } + output: + from: . | length \ No newline at end of file diff --git a/api/src/test/resources/features/checkcarvitals.json b/api/src/test/resources/features/checkcarvitals.json deleted file mode 100644 index 6a66841a..00000000 --- a/api/src/test/resources/features/checkcarvitals.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "id": "checkcarvitals", - "name": "Check Car Vitals Workflow", - "version": "1.0", - "specVersion": "0.8", - "start": "WhenCarIsOn", - "states": [ - { - "name": "WhenCarIsOn", - "type": "event", - "onEvents": [ - { - "eventRefs": ["CarTurnedOnEvent"] - } - ], - "transition": "DoCarVitalsChecks" - }, - { - "name": "DoCarVitalsChecks", - "type": "operation", - "actions": [ - { - "subFlowRef": { - "workflowId": "vitalscheck" - } - } - ], - "transition": "WaitForCarStopped" - }, - { - "name": "WaitForCarStopped", - "type": "event", - "onEvents": [ - { - "eventRefs": ["CarTurnedOffEvent"], - "actions": [ - { - "eventRef": { - "triggerEventRef": "StopVitalsCheck", - "resultEventRef": "VitalsCheckingStopped" - } - } - ] - } - ], - "end": true - } - ], - "events": [ - { - "name": "CarTurnedOnEvent", - "type": "car.events", - "source": "my/car" - }, - { - "name": "CarTurnedOffEvent", - "type": "car.events", - "source": "my/car" - }, - { - "name": "StopVitalsCheck", - "type": "car.events", - "source": "my/car" - }, - { - "name": "VitalsCheckingStopped", - "type": "car.events", - "source": "my/car" - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/checkcarvitals.yml b/api/src/test/resources/features/checkcarvitals.yml deleted file mode 100644 index 86a00d1d..00000000 --- a/api/src/test/resources/features/checkcarvitals.yml +++ /dev/null @@ -1,41 +0,0 @@ -id: checkcarvitals -name: Check Car Vitals Workflow -version: '1.0' -specVersion: '0.8' -start: WhenCarIsOn -states: - - name: WhenCarIsOn - type: event - onEvents: - - eventRefs: - - CarTurnedOnEvent - transition: DoCarVitalsChecks - - name: DoCarVitalsChecks - type: operation - actions: - - subFlowRef: - workflowId: vitalscheck - transition: WaitForCarStopped - - name: WaitForCarStopped - type: event - onEvents: - - eventRefs: - - CarTurnedOffEvent - actions: - - eventRef: - triggerEventRef: StopVitalsCheck - resultEventRef: VitalsCheckingStopped - end: true -events: - - name: CarTurnedOnEvent - type: car.events - source: my/car - - name: CarTurnedOffEvent - type: car.events - source: my/car - - name: StopVitalsCheck - type: car.events - source: my/car - - name: VitalsCheckingStopped - type: car.events - source: my/car diff --git a/api/src/test/resources/features/compensationworkflow.json b/api/src/test/resources/features/compensationworkflow.json deleted file mode 100644 index f7771655..00000000 --- a/api/src/test/resources/features/compensationworkflow.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "id": "CompensationWorkflow", - "name": "Compensation Workflow", - "version": "1.0", - "specVersion": "0.8", - "states": [ - { - "name": "NewItemPurchase", - "type": "event", - "onEvents": [ - { - "eventRefs": [ - "NewPurchase" - ], - "actions": [ - { - "functionRef": { - "refName": "DebitCustomerFunction", - "arguments": { - "customerid": "${ .purchase.customerid }", - "amount": "${ .purchase.amount }" - } - } - }, - { - "functionRef": { - "refName": "SendPurchaseConfirmationEmailFunction", - "arguments": { - "customerid": "${ .purchase.customerid }" - } - } - } - ] - } - ], - "compensatedBy": "CancelPurchase", - "transition": "SomeNextWorkflowState" - }, - { - "name": "CancelPurchase", - "type": "operation", - "usedForCompensation": true, - "actions": [ - { - "functionRef": { - "refName": "CreditCustomerFunction", - "arguments": { - "customerid": "${ .purchase.customerid }", - "amount": "${ .purchase.amount }" - } - } - }, - { - "functionRef": { - "refName": "SendPurchaseCancellationEmailFunction", - "arguments": { - "customerid": "${ .purchase.customerid }" - } - } - } - ] - } - ], - "events": [ - { - "name": "NewItemPurchase", - "source": "purchasesource", - "type": "org.purchases" - } - ], - "functions": [ - { - "name": "DebitCustomerFunction", - "operation": "http://myapis.org/application.json#debit" - }, - { - "name": "SendPurchaseConfirmationEmailFunction", - "operation": "http://myapis.org/application.json#confirmationemail" - }, - { - "name": "SendPurchaseCancellationEmailFunction", - "operation": "http://myapis.org/application.json#cancellationemail" - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/compensationworkflow.yml b/api/src/test/resources/features/compensationworkflow.yml deleted file mode 100644 index b8963838..00000000 --- a/api/src/test/resources/features/compensationworkflow.yml +++ /dev/null @@ -1,46 +0,0 @@ -id: CompensationWorkflow -name: Compensation Workflow -version: '1.0' -specVersion: '0.8' -states: - - name: NewItemPurchase - type: event - onEvents: - - eventRefs: - - NewPurchase - actions: - - functionRef: - refName: DebitCustomerFunction - arguments: - customerid: "${ .purchase.customerid }" - amount: "${ .purchase.amount }" - - functionRef: - refName: SendPurchaseConfirmationEmailFunction - arguments: - customerid: "${ .purchase.customerid }" - compensatedBy: CancelPurchase - transition: SomeNextWorkflowState - - name: CancelPurchase - type: operation - usedForCompensation: true - actions: - - functionRef: - refName: CreditCustomerFunction - arguments: - customerid: "${ .purchase.customerid }" - amount: "${ .purchase.amount }" - - functionRef: - refName: SendPurchaseCancellationEmailFunction - arguments: - customerid: "${ .purchase.customerid }" -events: - - name: NewItemPurchase - source: purchasesource - type: org.purchases -functions: - - name: DebitCustomerFunction - operation: http://myapis.org/application.json#debit - - name: SendPurchaseConfirmationEmailFunction - operation: http://myapis.org/application.json#confirmationemail - - name: SendPurchaseCancellationEmailFunction - operation: http://myapis.org/application.json#cancellationemail diff --git a/api/src/test/resources/features/composite.yaml b/api/src/test/resources/features/composite.yaml new file mode 100644 index 00000000..28c448c2 --- /dev/null +++ b/api/src/test/resources/features/composite.yaml @@ -0,0 +1,17 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: composite-sequential +do: + setRGB: + execute: + sequentially: + setRed: + set: + colors: ${ .colors + ["red"] } + setGreen: + set: + colors: ${ .colors + ["green"] } + setBlue: + set: + colors: ${ .colors + ["blue"] } diff --git a/api/src/test/resources/features/constants.json b/api/src/test/resources/features/constants.json deleted file mode 100644 index 93dd9452..00000000 --- a/api/src/test/resources/features/constants.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "id": "secrets", - "version": "1.0", - "specVersion": "0.8", - "name": "Custom secrets flow", - "expressionLang": "abc", - "start": "TestFunctionRefs", - "constants": { - "Translations": { - "Dog": { - "Serbian": "pas", - "Spanish": "perro", - "French": "chien" - } - } - }, - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/constants.yml b/api/src/test/resources/features/constants.yml deleted file mode 100644 index 083f0433..00000000 --- a/api/src/test/resources/features/constants.yml +++ /dev/null @@ -1,23 +0,0 @@ -id: secrets -version: '1.0' -specVersion: '0.8' -name: Custom secrets flow -expressionLang: abc -start: TestFunctionRefs -constants: - Translations: - Dog: - Serbian: pas - Spanish: perro - French: chien -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true diff --git a/api/src/test/resources/features/constantsRef.json b/api/src/test/resources/features/constantsRef.json deleted file mode 100644 index cd0fcb60..00000000 --- a/api/src/test/resources/features/constantsRef.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "secrets", - "version": "1.0", - "specVersion": "0.8", - "name": "Custom secrets flow", - "expressionLang": "abc", - "start": "TestFunctionRefs", - "constants": "constantValues.json", - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actions": [], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/constantsRef.yml b/api/src/test/resources/features/constantsRef.yml deleted file mode 100644 index cdc48332..00000000 --- a/api/src/test/resources/features/constantsRef.yml +++ /dev/null @@ -1,14 +0,0 @@ -id: secrets -version: '1.0' -specVersion: '0.8' -name: Custom secrets flow -expressionLang: abc -start: TestFunctionRefs -constants: - constantValues.json -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - end: true diff --git a/api/src/test/resources/features/continueasobject.json b/api/src/test/resources/features/continueasobject.json deleted file mode 100644 index a2c6462e..00000000 --- a/api/src/test/resources/features/continueasobject.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "id": "functionrefs", - "version": "1.0", - "specVersion": "0.8", - "name": "Customer Credit Check Workflow", - "description": "Perform Customer Credit Check", - "start": "TestFunctionRef", - "functions": [ - { - "name": "creditCheckFunction", - "operation": "http://myapis.org/creditcheckapi.json#doCreditCheck" - }, - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/creditcheckapi.json#rejectionEmail" - } - ], - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": { - "continueAs": { - "workflowId": "myworkflowid", - "version": "1.0", - "data": "${ .data }", - "workflowExecTimeout": { - "duration": "PT1M" - } - } - } - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/continueasobject.yml b/api/src/test/resources/features/continueasobject.yml deleted file mode 100644 index 8bc9dc2c..00000000 --- a/api/src/test/resources/features/continueasobject.yml +++ /dev/null @@ -1,28 +0,0 @@ -id: functionrefs -version: '1.0' -specVersion: '0.8' -name: Customer Credit Check Workflow -description: Perform Customer Credit Check -start: TestFunctionRef -functions: - - name: creditCheckFunction - operation: http://myapis.org/creditcheckapi.json#doCreditCheck - - name: sendRejectionEmailFunction - operation: http://myapis.org/creditcheckapi.json#rejectionEmail -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: - continueAs: - workflowId: myworkflowid - version: '1.0' - data: "${ .data }" - workflowExecTimeout: - duration: PT1M diff --git a/api/src/test/resources/features/continueasstring.json b/api/src/test/resources/features/continueasstring.json deleted file mode 100644 index 0e4b2b89..00000000 --- a/api/src/test/resources/features/continueasstring.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "functionrefs", - "version": "1.0", - "specVersion": "0.8", - "name": "Customer Credit Check Workflow", - "description": "Perform Customer Credit Check", - "start": "TestFunctionRef", - "functions": [ - { - "name": "creditCheckFunction", - "operation": "http://myapis.org/creditcheckapi.json#doCreditCheck" - }, - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/creditcheckapi.json#rejectionEmail" - } - ], - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": { - "continueAs": "myworkflowid" - } - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/continueasstring.yml b/api/src/test/resources/features/continueasstring.yml deleted file mode 100644 index a6175e20..00000000 --- a/api/src/test/resources/features/continueasstring.yml +++ /dev/null @@ -1,23 +0,0 @@ -id: functionrefs -version: '1.0' -specVersion: '0.8' -name: Customer Credit Check Workflow -description: Perform Customer Credit Check -start: TestFunctionRef -functions: - - name: creditCheckFunction - operation: http://myapis.org/creditcheckapi.json#doCreditCheck - - name: sendRejectionEmailFunction - operation: http://myapis.org/creditcheckapi.json#rejectionEmail -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: - continueAs: myworkflowid diff --git a/api/src/test/resources/features/data-flow.yaml b/api/src/test/resources/features/data-flow.yaml new file mode 100644 index 00000000..d1d76418 --- /dev/null +++ b/api/src/test/resources/features/data-flow.yaml @@ -0,0 +1,21 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: non-object-output +do: + getPetById1: + call: http + with: + method: get + endpoint: + uri: https://petstore.swagger.io/v2/pet/{petId} #simple interpolation, only possible with top level variables + output: + from: .id + getPetById2: + call: http + with: + method: get + endpoint: + uri: https://petstore.swagger.io/v2/pet/2 + output: + from: '{ ids: [ $input, .id ] }' diff --git a/api/src/test/resources/features/datainputschemaobj.json b/api/src/test/resources/features/datainputschemaobj.json deleted file mode 100644 index 79b183c3..00000000 --- a/api/src/test/resources/features/datainputschemaobj.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "id": "datainputschemaobj", - "version": "1.0", - "specVersion": "0.8", - "name": "Data Input Schema test", - "dataInputSchema": { - "schema":{ - "title": "MyJSONSchema", - "properties":{ - "firstName":{ - "type": "string" - }, - "lastName":{ - "type": "string" - } - } - }, - "failOnValidationErrors": false - }, - "start": "TestFunctionRefs", - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/datainputschemaobj.yml b/api/src/test/resources/features/datainputschemaobj.yml deleted file mode 100644 index b2073b46..00000000 --- a/api/src/test/resources/features/datainputschemaobj.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -id: datainputschemaobj -version: '1.0' -specVersion: '0.8' -name: Data Input Schema test -dataInputSchema: - schema: - title: MyJSONSchema - properties: - firstName: - type: string - lastName: - type: string - failOnValidationErrors: false -start: TestFunctionRefs -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true diff --git a/api/src/test/resources/features/datainputschemaobjstring.json b/api/src/test/resources/features/datainputschemaobjstring.json deleted file mode 100644 index b61bdd5c..00000000 --- a/api/src/test/resources/features/datainputschemaobjstring.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "datainputschemaobj", - "version": "1.0", - "specVersion": "0.8", - "name": "Data Input Schema test", - "dataInputSchema": "features/somejsonschema.json", - "start": "TestFunctionRefs", - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/datainputschemaobjstring.yml b/api/src/test/resources/features/datainputschemaobjstring.yml deleted file mode 100644 index fcf7c60c..00000000 --- a/api/src/test/resources/features/datainputschemaobjstring.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: datainputschemaobj -version: '1.0' -specVersion: '0.8' -name: Data Input Schema test -dataInputSchema: features/somejsonschema.json -start: TestFunctionRefs -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true diff --git a/api/src/test/resources/features/datainputschemastring.json b/api/src/test/resources/features/datainputschemastring.json deleted file mode 100644 index 822ed865..00000000 --- a/api/src/test/resources/features/datainputschemastring.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "id": "datainputschemaobj", - "version": "1.0", - "specVersion": "0.8", - "name": "Data Input Schema test", - "dataInputSchema": { - "schema": "features/somejsonschema.json", - "failOnValidationErrors": true - }, - "start": "TestFunctionRefs", - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/datainputschemastring.yml b/api/src/test/resources/features/datainputschemastring.yml deleted file mode 100644 index 326622e8..00000000 --- a/api/src/test/resources/features/datainputschemastring.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: datainputschemaobj -version: '1.0' -specVersion: '0.8' -name: Data Input Schema test -dataInputSchema: - schema: features/somejsonschema.json - failOnValidationErrors: true -start: TestFunctionRefs -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true diff --git a/api/src/test/resources/features/datainputschemawithnullschema.json b/api/src/test/resources/features/datainputschemawithnullschema.json deleted file mode 100644 index 54d01468..00000000 --- a/api/src/test/resources/features/datainputschemawithnullschema.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "id": "datainputschemaobj", - "version": "1.0", - "specVersion": "0.8", - "name": "Data Input Schema test", - "dataInputSchema": { - "schema": null, - "failOnValidationErrors": true - }, - "start": "TestFunctionRefs", - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/emit.yaml b/api/src/test/resources/features/emit.yaml new file mode 100644 index 00000000..d9bfabcd --- /dev/null +++ b/api/src/test/resources/features/emit.yaml @@ -0,0 +1,13 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: emit +do: + emitUserGreeted: + emit: + event: + with: + source: https://fake-source.com + type: com.fake-source.user.greeted.v1 + data: + greetings: ${ "Hello \(.user.firstName) \(.user.lastName)!" } diff --git a/api/src/test/resources/features/errors.json b/api/src/test/resources/features/errors.json deleted file mode 100644 index 3d57b47e..00000000 --- a/api/src/test/resources/features/errors.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "id": "functionrefparams", - "version": "1.0", - "specVersion": "0.8", - "name": "Function Ref Params Test", - "start": "AddPluto", - "autoRetries": true, - "errors": [ - { - "name": "ErrorA", - "code": "400" - }, - { - "name": "ErrorB", - "code": "500" - } - ], - "states": [ - { - "name": "AddPluto", - "type": "operation", - "actions": [ - { - "functionRef": "addPet", - "retryRef": "testRetry", - "nonRetryableErrors": ["A", "B"], - "condition": "${ .data }" - } - ], - "onErrors": [ - { - "errorRefs": ["A", "B"], - "end": true - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/errors.yml b/api/src/test/resources/features/errors.yml deleted file mode 100644 index 51327435..00000000 --- a/api/src/test/resources/features/errors.yml +++ /dev/null @@ -1,27 +0,0 @@ -id: functionrefparams -version: '1.0' -specVersion: '0.8' -name: Function Ref Params Test -start: AddPluto -autoRetries: true -errors: - - name: ErrorA - code: '400' - - name: ErrorB - code: '500' -states: - - name: AddPluto - type: operation - actions: - - functionRef: addPet - retryRef: testRetry - nonRetryableErrors: - - A - - B - condition: "${ .data }" - onErrors: - - errorRefs: - - A - - B - end: true - end: true diff --git a/api/src/test/resources/features/eventdefdataonly.json b/api/src/test/resources/features/eventdefdataonly.json deleted file mode 100644 index a181b864..00000000 --- a/api/src/test/resources/features/eventdefdataonly.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "id": "eventdefdataonly", - "version": "1.0", - "specVersion": "0.8", - "name": "Event Definition Data Only Test", - "description": "Event Definition Data Only Test", - "start": "CheckVisaStatus", - "events": [ - { - "name": "visaApprovedEvent", - "type": "VisaApproved", - "source": "visaCheckSource", - "dataOnly": false - }, - { - "name": "visaRejectedEvent", - "type": "VisaRejected", - "source": "visaCheckSource" - } - ], - "states":[ - { - "name":"CheckVisaStatus", - "type":"switch", - "eventConditions": [ - { - "eventRef": "visaApprovedEvent", - "transition": "HandleApprovedVisa" - }, - { - "eventRef": "visaRejectedEvent", - "transition": "HandleRejectedVisa" - } - ], - "timeouts": { - "eventTimeout": "PT1H" - }, - "defaultCondition": { - "transition": "HandleNoVisaDecision" - } - }, - { - "name": "HandleApprovedVisa", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleApprovedVisaWorkflowID" - } - ], - "end": true - }, - { - "name": "HandleRejectedVisa", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleRejectedVisaWorkflowID" - } - ], - "end": true - }, - { - "name": "HandleNoVisaDecision", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleNoVisaDecisionWorkflowId" - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/eventdefdataonly.yml b/api/src/test/resources/features/eventdefdataonly.yml deleted file mode 100644 index e67a9ede..00000000 --- a/api/src/test/resources/features/eventdefdataonly.yml +++ /dev/null @@ -1,41 +0,0 @@ -id: eventdefdataonly -version: '1.0' -specVersion: '0.8' -name: Event Definition Data Only Test -description: Event Definition Data Only Test -start: CheckVisaStatus -events: - - name: visaApprovedEvent - type: VisaApproved - source: visaCheckSource - dataOnly: false - - name: visaRejectedEvent - type: VisaRejected - source: visaCheckSource -states: - - name: CheckVisaStatus - type: switch - eventConditions: - - eventRef: visaApprovedEvent - transition: HandleApprovedVisa - - eventRef: visaRejectedEvent - transition: HandleRejectedVisa - timeouts: - eventTimeout: PT1H - defaultCondition: - transition: HandleNoVisaDecision - - name: HandleApprovedVisa - type: operation - actions: - - subFlowRef: handleApprovedVisaWorkflowID - end: true - - name: HandleRejectedVisa - type: operation - actions: - - subFlowRef: handleRejectedVisaWorkflowID - end: true - - name: HandleNoVisaDecision - type: operation - actions: - - subFlowRef: handleNoVisaDecisionWorkflowId - end: true diff --git a/api/src/test/resources/features/expressionlang.json b/api/src/test/resources/features/expressionlang.json deleted file mode 100644 index bf77ada8..00000000 --- a/api/src/test/resources/features/expressionlang.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "expressionlang", - "version": "1.0", - "specVersion": "0.8", - "name": "Custom expression lang", - "expressionLang": "abc", - "start": "TestFunctionRefs", - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/expressionlang.yml b/api/src/test/resources/features/expressionlang.yml deleted file mode 100644 index 9ae3ed1a..00000000 --- a/api/src/test/resources/features/expressionlang.yml +++ /dev/null @@ -1,17 +0,0 @@ -id: expressionlang -version: '1.0' -specVersion: '0.8' -name: Custom expression lang -expressionLang: abc -start: TestFunctionRefs -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/features/flow.yaml b/api/src/test/resources/features/flow.yaml new file mode 100644 index 00000000..631b25ac --- /dev/null +++ b/api/src/test/resources/features/flow.yaml @@ -0,0 +1,14 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: implicit-sequence +do: + setRed: + set: + colors: '${ .colors + [ "red" ] }' + setGreen: + set: + colors: '${ .colors + [ "green" ] }' + setBlue: + set: + colors: '${ .colors + [ "blue" ] }' diff --git a/api/src/test/resources/features/for.yaml b/api/src/test/resources/features/for.yaml new file mode 100644 index 00000000..b7bc9b6f --- /dev/null +++ b/api/src/test/resources/features/for.yaml @@ -0,0 +1,12 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: for +do: + forEachColor: + for: + each: color + in: '.colors' + do: + set: + processed: '${ { colors: (.processed.colors + [ $color ]), indexes: (.processed.indexes + [ $index ])} }' diff --git a/api/src/test/resources/features/functionrefjsonparams.json b/api/src/test/resources/features/functionrefjsonparams.json deleted file mode 100644 index ae7fd713..00000000 --- a/api/src/test/resources/features/functionrefjsonparams.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "id": "functionrefparams", - "version": "1.0", - "specVersion": "0.8", - "name": "Function Ref Params Test", - "start": "AddPluto", - "states": [ - { - "name": "AddPluto", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "addPet", - "arguments": { - "body": { - "name": "Pluto", - "tag": "${ .pet.tagnumber }" - }, - "id": 123, - "address": "My Address, 123 MyCity, MyCountry", - "owner": "${ .owner.name }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/functionrefjsonparams.yml b/api/src/test/resources/features/functionrefjsonparams.yml deleted file mode 100644 index 23b3cae5..00000000 --- a/api/src/test/resources/features/functionrefjsonparams.yml +++ /dev/null @@ -1,19 +0,0 @@ -id: functionrefparams -version: '1.0' -specVersion: '0.8' -name: Function Ref Params Test -start: AddPluto -states: - - name: AddPluto - type: operation - actions: - - functionRef: - refName: addPet - arguments: - body: - name: Pluto - tag: "${ .pet.tagnumber }" - id: 123 - address: My Address, 123 MyCity, MyCountry - owner: "${ .owner.name }" - end: true diff --git a/api/src/test/resources/features/functionrefnoparams.json b/api/src/test/resources/features/functionrefnoparams.json deleted file mode 100644 index c150f1c5..00000000 --- a/api/src/test/resources/features/functionrefnoparams.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "id": "functionrefparams", - "version": "1.0", - "specVersion": "0.8", - "name": "Function Ref Params Test", - "start": "AddPluto", - "states": [ - { - "name": "AddPluto", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "addPet" - } - }, - { - "functionRef": "addPet" - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/functionrefnoparams.yml b/api/src/test/resources/features/functionrefnoparams.yml deleted file mode 100644 index bc2bf078..00000000 --- a/api/src/test/resources/features/functionrefnoparams.yml +++ /dev/null @@ -1,13 +0,0 @@ -id: functionrefparams -version: '1.0' -specVersion: '0.8' -name: Function Ref Params Test -start: AddPluto -states: - - name: AddPluto - type: operation - actions: - - functionRef: - refName: addPet - - functionRef: addPet - end: true \ No newline at end of file diff --git a/api/src/test/resources/features/functionrefs.json b/api/src/test/resources/features/functionrefs.json deleted file mode 100644 index e3333b28..00000000 --- a/api/src/test/resources/features/functionrefs.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "id": "functionrefs", - "version": "1.0", - "specVersion": "0.8", - "name": "Customer Credit Check Workflow", - "description": "Perform Customer Credit Check", - "start": "TestFunctionRef", - "functions": [ - { - "name": "creditCheckFunction", - "operation": "http://myapis.org/creditcheckapi.json#doCreditCheck" - }, - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/creditcheckapi.json#rejectionEmail" - } - ], - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/functionrefs.yml b/api/src/test/resources/features/functionrefs.yml deleted file mode 100644 index 289a6e7f..00000000 --- a/api/src/test/resources/features/functionrefs.yml +++ /dev/null @@ -1,22 +0,0 @@ -id: functionrefs -version: '1.0' -specVersion: '0.8' -name: Customer Credit Check Workflow -description: Perform Customer Credit Check -start: TestFunctionRefs -functions: - - name: creditCheckFunction - operation: http://myapis.org/creditcheckapi.json#doCreditCheck - - name: sendRejectionEmailFunction - operation: http://myapis.org/creditcheckapi.json#rejectionEmail -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/features/functiontypes.json b/api/src/test/resources/features/functiontypes.json deleted file mode 100644 index 6452e359..00000000 --- a/api/src/test/resources/features/functiontypes.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "id": "functiontypes", - "version": "1.0", - "specVersion": "0.8", - "name": "Function Types Workflow", - "description": "Determine if applicant request is valid", - "start": "CheckFunctions", - "functions": [ - { - "name": "restFunction", - "operation": "http://myapis.org/applicationapi.json#emailRejection" - }, - { - "name": "expressionFunction", - "operation": ".my.data", - "type" : "expression" - } - ], - "states":[ - { - "name":"CheckFunctions", - "type":"operation", - "actions":[ - { - "functionRef": { - "refName": "restFunction", - "arguments": { - "data": "${ fn(expressionFunction) }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/functiontypes.yml b/api/src/test/resources/features/functiontypes.yml deleted file mode 100644 index 2e4ec926..00000000 --- a/api/src/test/resources/features/functiontypes.yml +++ /dev/null @@ -1,21 +0,0 @@ -id: functiontypes -version: '1.0' -specVersion: '0.8' -name: Function Types Workflow -description: Determine if applicant request is valid -start: CheckFunctions -functions: - - name: restFunction - operation: http://myapis.org/applicationapi.json#emailRejection - - name: expressionFunction - operation: ".my.data" - type: expression -states: - - name: CheckFunctions - type: operation - actions: - - functionRef: - refName: restFunction - arguments: - data: "${ fn(expressionFunction) }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/features/invoke.json b/api/src/test/resources/features/invoke.json deleted file mode 100644 index bf69f433..00000000 --- a/api/src/test/resources/features/invoke.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "id": "invoketest", - "version": "1.0", - "specVersion": "0.8", - "name": "Invoke Test", - "description": "Invoke Test", - "start": "TestInvoke", - "states": [ - { - "name": "TestInvoke", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "invoke": "async" - } - }, - { - "subFlowRef": { - "workflowId": "subflowrefworkflowid", - "version": "1.0", - "invoke": "async", - "onParentComplete": "continue" - } - }, - { - "eventRef": { - "triggerEventRef": "abc", - "resultEventRef": "123", - "invoke": "async" - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/invoke.yml b/api/src/test/resources/features/invoke.yml deleted file mode 100644 index 88e25073..00000000 --- a/api/src/test/resources/features/invoke.yml +++ /dev/null @@ -1,24 +0,0 @@ -id: invoketest -version: '1.0' -specVersion: '0.8' -name: Invoke Test -description: Invoke Test -start: TestInvoke -states: - - name: TestInvoke - type: operation - actionMode: sequential - actions: - - functionRef: - refName: sendRejectionEmailFunction - invoke: async - - subFlowRef: - workflowId: subflowrefworkflowid - version: '1.0' - invoke: async - onParentComplete: continue - - eventRef: - triggerEventRef: abc - resultEventRef: '123' - invoke: async - end: true diff --git a/api/src/test/resources/features/keepactiveexectimeout.json b/api/src/test/resources/features/keepactiveexectimeout.json deleted file mode 100644 index fe613bab..00000000 --- a/api/src/test/resources/features/keepactiveexectimeout.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "id": "keepactiveexectimeout", - "name": "Keep Active and Exec Timeout Test Workflow", - "version": "1.0", - "specVersion": "0.8", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1H", - "runBefore": "GenerateReport" - } - }, - "keepActive": true, - "states": [ - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/keepactiveexectimeout.yml b/api/src/test/resources/features/keepactiveexectimeout.yml deleted file mode 100644 index 22e4b439..00000000 --- a/api/src/test/resources/features/keepactiveexectimeout.yml +++ /dev/null @@ -1,10 +0,0 @@ -id: keepactiveexectimeout -name: Keep Active and Exec Timeout Test Workflow -version: '1.0' -specVersion: '0.8' -timeouts: - workflowExecTimeout: - duration: PT1H - runBefore: GenerateReport -keepActive: true -states: [] diff --git a/api/src/test/resources/features/longstart.json b/api/src/test/resources/features/longstart.json deleted file mode 100644 index f2ea4ae1..00000000 --- a/api/src/test/resources/features/longstart.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "id": "longstart", - "version": "1.0", - "specVersion": "0.8", - "name": "Long start", - "start": { - "stateName": "TestFunctionRefs", - "schedule": { - "cron": "0 0/15 * * * ?" - } - }, - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/longstart.yml b/api/src/test/resources/features/longstart.yml deleted file mode 100644 index 6151632b..00000000 --- a/api/src/test/resources/features/longstart.yml +++ /dev/null @@ -1,19 +0,0 @@ -id: longstart -version: '1.0' -specVersion: '0.8' -name: Long start -start: - stateName: TestFunctionRefs - schedule: - cron: 0 0/15 * * * ? -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/features/raise.yaml b/api/src/test/resources/features/raise.yaml new file mode 100644 index 00000000..48e3e572 --- /dev/null +++ b/api/src/test/resources/features/raise.yaml @@ -0,0 +1,11 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: raise-custom-error +do: + raiseComplianceError: + raise: + error: + status: 400 + type: https://serverlessworkflow.io/errors/types/compliance + title: Compliance Error diff --git a/api/src/test/resources/features/retriesprops.json b/api/src/test/resources/features/retriesprops.json deleted file mode 100644 index 397a8672..00000000 --- a/api/src/test/resources/features/retriesprops.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "id": "TestRetriesProps", - "name": "Retries props test", - "version": "1.0", - "specVersion": "0.8", - "start": "Test State", - "retries": [ - { - "name": "Test Retries", - "delay": "PT1M", - "maxDelay": "PT2M", - "increment": "PT2S", - "multiplier": "1.2", - "maxAttempts": "20", - "jitter": "0.4" - } - ], - "states": [ - { - "name": "Test States", - "type": "operation", - "actions": [ - ], - "onErrors": [ - { - "errorRef": "TimeoutError", - "end": true - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/retriesprops.yml b/api/src/test/resources/features/retriesprops.yml deleted file mode 100644 index 01d3d04a..00000000 --- a/api/src/test/resources/features/retriesprops.yml +++ /dev/null @@ -1,21 +0,0 @@ -id: TestRetriesProps -name: Retries props test -version: '1.0' -specVersion: '0.8' -start: Test State -retries: - - name: Test Retries - delay: PT1M - maxDelay: PT2M - increment: PT2S - multiplier: '1.2' - maxAttempts: '20' - jitter: '0.4' -states: - - name: Test States - type: operation - actions: [] - onErrors: - - errorRef: TimeoutError - end: true - end: true diff --git a/api/src/test/resources/features/secrets.json b/api/src/test/resources/features/secrets.json deleted file mode 100644 index 06939379..00000000 --- a/api/src/test/resources/features/secrets.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "id": "secrets", - "version": "1.0", - "specVersion": "0.8", - "name": "Custom secrets flow", - "expressionLang": "abc", - "start": "TestFunctionRefs", - "secrets": ["secret1", "secret2", "secret3"], - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/secrets.yml b/api/src/test/resources/features/secrets.yml deleted file mode 100644 index 6ca947af..00000000 --- a/api/src/test/resources/features/secrets.yml +++ /dev/null @@ -1,21 +0,0 @@ -id: secrets -version: '1.0' -specVersion: '0.8' -name: Custom secrets flow -expressionLang: abc -start: TestFunctionRefs -secrets: - - secret1 - - secret2 - - secret3 -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true diff --git a/api/src/test/resources/features/set.yaml b/api/src/test/resources/features/set.yaml new file mode 100644 index 00000000..794176a3 --- /dev/null +++ b/api/src/test/resources/features/set.yaml @@ -0,0 +1,10 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: set +do: + initialize: + set: + shape: circle + size: ${ .configuration.size } + fill: ${ .configuration.fill } diff --git a/api/src/test/resources/features/shortstart.json b/api/src/test/resources/features/shortstart.json deleted file mode 100644 index b1b75926..00000000 --- a/api/src/test/resources/features/shortstart.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "shortstart", - "version": "1.0", - "specVersion": "0.8", - "name": "Short start", - "start": "TestFunctionRefs", - "states": [ - { - "name": "TestFunctionRefs", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "creditCheckFunction" - }, - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/shortstart.yml b/api/src/test/resources/features/shortstart.yml deleted file mode 100644 index 302ff182..00000000 --- a/api/src/test/resources/features/shortstart.yml +++ /dev/null @@ -1,16 +0,0 @@ -id: shortstart -version: '1.0' -specVersion: '0.8' -name: Short start -start: TestFunctionRefs -states: - - name: TestFunctionRefs - type: operation - actionMode: sequential - actions: - - functionRef: creditCheckFunction - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/features/simplecron.json b/api/src/test/resources/features/simplecron.json deleted file mode 100644 index bbe25672..00000000 --- a/api/src/test/resources/features/simplecron.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "id": "checkInbox", - "name": "Check Inbox Workflow", - "description": "Periodically Check Inbox", - "version": "1.0", - "specVersion": "0.8", - "start": { - "stateName": "CheckInbox", - "schedule": { - "cron": "0 0/15 * * * ?" - } - }, - "functions": [ - { - "name": "checkInboxFunction", - "operation": "http://myapis.org/inboxapi.json#checkNewMessages" - }, - { - "name": "sendTextFunction", - "operation": "http://myapis.org/inboxapi.json#sendText" - } - ], - "states": [ - { - "name": "CheckInbox", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "checkInboxFunction" - } - ], - "transition": "SendTextForHighPrioriry" - }, - { - "name": "SendTextForHighPrioriry", - "type": "foreach", - "inputCollection": "${ .messages }", - "iterationParam": "singlemessage", - "actions": [ - { - "functionRef": { - "refName": "sendTextFunction", - "arguments": { - "message": "${ .singlemessage }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/simplecron.yml b/api/src/test/resources/features/simplecron.yml deleted file mode 100644 index ed443de1..00000000 --- a/api/src/test/resources/features/simplecron.yml +++ /dev/null @@ -1,31 +0,0 @@ -id: checkInbox -name: Check Inbox Workflow -description: Periodically Check Inbox -version: '1.0' -specVersion: '0.8' -start: - stateName: CheckInbox - schedule: - cron: 0 0/15 * * * ? -functions: - - name: checkInboxFunction - operation: http://myapis.org/inboxapi.json#checkNewMessages - - name: sendTextFunction - operation: http://myapis.org/inboxapi.json#sendText -states: - - name: CheckInbox - type: operation - actionMode: sequential - actions: - - functionRef: checkInboxFunction - transition: SendTextForHighPrioriry - - name: SendTextForHighPrioriry - type: foreach - inputCollection: "${ .messages }" - iterationParam: singlemessage - actions: - - functionRef: - refName: sendTextFunction - arguments: - message: "${ .singlemessage }" - end: true \ No newline at end of file diff --git a/api/src/test/resources/features/simpleschedule.json b/api/src/test/resources/features/simpleschedule.json deleted file mode 100644 index f1dd9f95..00000000 --- a/api/src/test/resources/features/simpleschedule.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "id": "handleCarAuctionBid", - "version": "1.0", - "specVersion": "0.8", - "name": "Car Auction Bidding Workflow", - "description": "Store a single bid whole the car auction is active", - "start": { - "stateName": "StoreCarAuctionBid", - "schedule": "2020-03-20T09:00:00Z/2020-03-20T15:00:00Z" - }, - "functions": [ - { - "name": "StoreBidFunction", - "operation": "http://myapis.org/carauctionapi.json#storeBid" - } - ], - "events": [ - { - "name": "CarBidEvent", - "type": "carBidMadeType", - "source": "carBidEventSource" - } - ], - "states": [ - { - "name": "StoreCarAuctionBid", - "type": "event", - "exclusive": true, - "onEvents": [ - { - "eventRefs": [ - "CarBidEvent" - ], - "actions": [ - { - "functionRef": { - "refName": "StoreBidFunction", - "arguments": { - "bid": "${ .bid }" - } - } - } - ] - } - ], - "end": { - "terminate": true - } - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/simpleschedule.yml b/api/src/test/resources/features/simpleschedule.yml deleted file mode 100644 index c38bce8d..00000000 --- a/api/src/test/resources/features/simpleschedule.yml +++ /dev/null @@ -1,29 +0,0 @@ -id: handleCarAuctionBid -version: '1.0' -specVersion: '0.8' -name: Car Auction Bidding Workflow -description: Store a single bid whole the car auction is active -start: - stateName: StoreCarAuctionBid - schedule: 2020-03-20T09:00:00Z/2020-03-20T15:00:00Z -functions: - - name: StoreBidFunction - operation: http://myapis.org/carauctionapi.json#storeBid -events: - - name: CarBidEvent - type: carBidMadeType - source: carBidEventSource -states: - - name: StoreCarAuctionBid - type: event - exclusive: true - onEvents: - - eventRefs: - - CarBidEvent - actions: - - functionRef: - refName: StoreBidFunction - arguments: - bid: "${ .bid }" - end: - terminate: true \ No newline at end of file diff --git a/api/src/test/resources/features/somejsonschema.json b/api/src/test/resources/features/somejsonschema.json deleted file mode 100644 index a8710e0b..00000000 --- a/api/src/test/resources/features/somejsonschema.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema": { - "title": "MyJSONSchema", - "properties":{ - "firstName":{ - "type": "string" - }, - "lastName":{ - "type": "string" - } - } - } -} \ No newline at end of file diff --git a/api/src/test/resources/features/subflowref.json b/api/src/test/resources/features/subflowref.json deleted file mode 100644 index a9e2bf0b..00000000 --- a/api/src/test/resources/features/subflowref.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "id": "subflowrefworkflow", - "version": "1.0", - "specVersion": "0.8", - "name": "SubflowRef Workflow", - "start": "SubflowRef", - "states":[ - { - "name": "SubflowRef", - "type": "operation", - "actions": [ - { - "subFlowRef": "subflowRefReference" - }, - { - "subFlowRef": { - "workflowId": "subflowrefworkflowid", - "version": "1.0" - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/subflowref.yml b/api/src/test/resources/features/subflowref.yml deleted file mode 100644 index a95f8dfd..00000000 --- a/api/src/test/resources/features/subflowref.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -id: subflowrefworkflow -version: '1.0' -specVersion: '0.8' -name: SubflowRef Workflow -start: SubflowRef -states: - - name: SubflowRef - type: operation - actions: - - subFlowRef: subflowRefReference - - subFlowRef: - workflowId: subflowrefworkflowid - version: '1.0' - end: true diff --git a/api/src/test/resources/features/switch.yaml b/api/src/test/resources/features/switch.yaml new file mode 100644 index 00000000..f299b5cc --- /dev/null +++ b/api/src/test/resources/features/switch.yaml @@ -0,0 +1,28 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: switch-match +do: + switchColor: + switch: + red: + when: '.color == "red"' + then: setRed + green: + when: '.color == "green"' + then: setGreen + blue: + when: '.color == "blue"' + then: setBlue + setRed: + set: + colors: '${ .colors + [ "red" ] }' + then: end + setGreen: + set: + colors: '${ .colors + [ "green" ] }' + then: end + setBlue: + set: + colors: '${ .colors + [ "blue" ] }' + then: end diff --git a/api/src/test/resources/features/timeouts.json b/api/src/test/resources/features/timeouts.json deleted file mode 100644 index 217da047..00000000 --- a/api/src/test/resources/features/timeouts.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "id": "timeouts", - "name": "Timeouts Workflow", - "version": "1.0", - "specVersion": "0.8", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1H", - "runBefore": "GenerateReport" - } - }, - "start": "FirstState", - "states": [ - { - "name": "FirstState", - "type": "event", - "onEvents": [ - { - "eventRefs": ["someEventRef"] - } - ], - "timeouts": { - "stateExecTimeout": "PT5M", - "eventTimeout": "PT2M" - }, - "transition": "SecondState" - }, - { - "name": "SecondState", - "type": "parallel", - "completionType": "allOf", - "branches": [ - { - "name": "ShortDelayBranch", - "timeouts": { - "branchExecTimeout": "PT3S" - } - }, - { - "name": "LongDelayBranch", - "timeouts": { - "branchExecTimeout": "PT4S" - } - } - ], - "timeouts": { - "stateExecTimeout": "PT5M" - }, - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/timeouts.yml b/api/src/test/resources/features/timeouts.yml deleted file mode 100644 index 94280b61..00000000 --- a/api/src/test/resources/features/timeouts.yml +++ /dev/null @@ -1,32 +0,0 @@ -id: timeouts -name: Timeouts Workflow -version: '1.0' -specVersion: '0.8' -timeouts: - workflowExecTimeout: - duration: PT1H - runBefore: GenerateReport -start: FirstState -states: - - name: FirstState - type: event - onEvents: - - eventRefs: - - someEventRef - timeouts: - stateExecTimeout: PT5M - eventTimeout: PT2M - transition: SecondState - - name: SecondState - type: parallel - completionType: allOf - branches: - - name: ShortDelayBranch - timeouts: - branchExecTimeout: PT3S - - name: LongDelayBranch - timeouts: - branchExecTimeout: PT4S - timeouts: - stateExecTimeout: PT5M - end: true diff --git a/api/src/test/resources/features/transitions.json b/api/src/test/resources/features/transitions.json deleted file mode 100644 index ed7b7626..00000000 --- a/api/src/test/resources/features/transitions.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "id": "transitions", - "version": "1.0", - "specVersion": "0.8", - "name": "Transitions Workflow", - "start": "DifferentTransitionsTestState", - "description": "Transitions Workflow", - "functions": "features/applicantrequestfunctions.json", - "retries": "features/applicantrequestretries.json", - "states":[ - { - "name":"DifferentTransitionsTestState", - "type":"switch", - "dataConditions": [ - { - "condition": "${ .applicants[?(@.age >= 18)] }", - "transition": "StartApplication" - }, - { - "condition": "${ .applicants[?(@.age < 18)] }", - "transition": { - "nextState": "RejectApplication", - "produceEvents": [ - { - "eventRef": "provisioningCompleteEvent", - "data": "${ .provisionedOrders }", - "contextAttributes": { - "order_location": "IN", - "order_type": "online" - } - } - ] - } - } - ], - "defaultCondition": { - "transition": { - "nextState": "RejectApplication", - "compensate": true - } - } - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/transitions.yml b/api/src/test/resources/features/transitions.yml deleted file mode 100644 index 3ec34ae4..00000000 --- a/api/src/test/resources/features/transitions.yml +++ /dev/null @@ -1,27 +0,0 @@ -id: transitions -version: '1.0' -specVersion: '0.8' -name: Transitions Workflow -description: Transitions Workflow -start: DifferentTransitionsTestState -functions: features/applicantrequestfunctions.json -retries: features/applicantrequestretries.json -states: - - name: DifferentTransitionsTestState - type: switch - dataConditions: - - condition: "${ .applicants[?(@.age >= 18)] }" - transition: StartApplication - - condition: "${ .applicants[?(@.age < 18)] }" - transition: - nextState: RejectApplication - produceEvents: - - eventRef: provisioningCompleteEvent - data: "${ .provisionedOrders }" - contextAttributes: - "order_location": "IN" - "order_type": "online" - defaultCondition: - transition: - nextState: RejectApplication - compensate: true \ No newline at end of file diff --git a/api/src/test/resources/features/try.yaml b/api/src/test/resources/features/try.yaml new file mode 100644 index 00000000..0f028588 --- /dev/null +++ b/api/src/test/resources/features/try.yaml @@ -0,0 +1,21 @@ +document: + dsl: 1.0.0-alpha1 + namespace: default + name: try-catch-404 +do: + tryGetPet: + try: + call: http + with: + method: get + endpoint: + uri: https://petstore.swagger.io/v2/pet/getPetByName/{petName} + catch: + errors: + with: + type: https://serverlessworkflow.io/dsl/errors/types/communication + status: 404 + as: err + do: + set: + error: ${ $err } diff --git a/api/src/test/resources/features/vetappointment.json b/api/src/test/resources/features/vetappointment.json deleted file mode 100644 index 944fad06..00000000 --- a/api/src/test/resources/features/vetappointment.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "id": "VetAppointmentWorkflow", - "name": "Vet Appointment Workflow", - "description": "Vet service call via events", - "version": "1.0", - "specVersion": "0.8", - "start": "MakeVetAppointmentState", - "events": "features/vetappointmenteventrefs.json", - "retries": "features/vetappointmentretries.json", - "states": [ - { - "name": "MakeVetAppointmentState", - "type": "operation", - "actions": [ - { - "name": "MakeAppointmentAction", - "eventRef": { - "triggerEventRef": "MakeVetAppointment", - "data": "${ .patientInfo }", - "resultEventRef": "VetAppointmentInfo" - }, - "actionDataFilter": { - "results": "${ .appointmentInfo }" - } - } - ], - "timeouts": { - "actionExecTimeout": "PT15M" - }, - "onErrors": [ - { - "errorRef": "TimeoutError", - "end": true - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/vetappointment.yml b/api/src/test/resources/features/vetappointment.yml deleted file mode 100644 index e47baf8f..00000000 --- a/api/src/test/resources/features/vetappointment.yml +++ /dev/null @@ -1,25 +0,0 @@ -id: VetAppointmentWorkflow -name: Vet Appointment Workflow -description: Vet service call via events -version: '1.0' -specVersion: '0.8' -start: MakeVetAppointmentState -events: features/vetappointmenteventrefs.json -retries: features/vetappointmentretries.json -states: - - name: MakeVetAppointmentState - type: operation - actions: - - name: MakeAppointmentAction - eventRef: - triggerEventRef: MakeVetAppointment - data: "${ .patientInfo }" - resultEventRef: VetAppointmentInfo - actionDataFilter: - results: "${ .appointmentInfo }" - timeouts: - actionExecTimeout: PT15M - onErrors: - - errorRef: TimeoutError - end: true - end: true diff --git a/api/src/test/resources/features/vetappointmenteventrefs.json b/api/src/test/resources/features/vetappointmenteventrefs.json deleted file mode 100644 index 6d021888..00000000 --- a/api/src/test/resources/features/vetappointmenteventrefs.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "events": [ - { - "name": "MakeVetAppointment", - "source": "VetServiceSoure", - "kind": "produced" - }, - { - "name": "VetAppointmentInfo", - "source": "VetServiceSource", - "kind": "consumed" - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/vetappointmenteventrefs.yml b/api/src/test/resources/features/vetappointmenteventrefs.yml deleted file mode 100644 index 922e6bd7..00000000 --- a/api/src/test/resources/features/vetappointmenteventrefs.yml +++ /dev/null @@ -1,7 +0,0 @@ -events: - - name: MakeVetAppointment - source: VetServiceSoure - kind: produced - - name: VetAppointmentInfo - source: VetServiceSource - kind: consumed diff --git a/api/src/test/resources/features/vetappointmentretries.json b/api/src/test/resources/features/vetappointmentretries.json deleted file mode 100644 index 40f83b55..00000000 --- a/api/src/test/resources/features/vetappointmentretries.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "retries": [ - { - "name": "TimeoutRetryStrategy", - "delay": "PT1M", - "maxAttempts": "5" - } - ] -} \ No newline at end of file diff --git a/api/src/test/resources/features/vetappointmentretries.yml b/api/src/test/resources/features/vetappointmentretries.yml deleted file mode 100644 index fa4c810d..00000000 --- a/api/src/test/resources/features/vetappointmentretries.yml +++ /dev/null @@ -1,4 +0,0 @@ -retries: - - name: TimeoutRetryStrategy - delay: PT1M - maxAttempts: '5' diff --git a/custom-generator/pom.xml b/custom-generator/pom.xml new file mode 100644 index 00000000..c48b5bfa --- /dev/null +++ b/custom-generator/pom.xml @@ -0,0 +1,39 @@ + + 4.0.0 + + io.serverlessworkflow + serverlessworkflow-parent + 7.0.0-SNAPSHOT + + custom-generator + + + org.jsonschema2pojo + jsonschema2pojo-core + + + + + + com.spotify.fmt + fmt-maven-plugin + + src/main/java + src/test/java + false + .*\.java + false + false + + + + + + format + + + + + + + \ No newline at end of file diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java new file mode 100644 index 00000000..be36d3d5 --- /dev/null +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java @@ -0,0 +1,59 @@ +package io.serverlessworkflow.generator; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.sun.codemodel.JClassContainer; +import com.sun.codemodel.JType; +import java.util.Iterator; +import org.jsonschema2pojo.Schema; +import org.jsonschema2pojo.rules.Rule; +import org.jsonschema2pojo.rules.RuleFactory; +import org.jsonschema2pojo.rules.SchemaRule; + +public class UnreferencedFactory extends RuleFactory { + @Override + public Rule getSchemaRule() { + return new MySchemaRule(this); + } + + private class MySchemaRule extends SchemaRule { + + public MySchemaRule(UnreferencedFactory jsonSchemaRuleFactory) { + super(jsonSchemaRuleFactory); + } + + @Override + public JType apply( + String nodeName, + JsonNode schemaNode, + JsonNode parent, + JClassContainer generatableType, + Schema schema) { + JType result = super.apply(nodeName, schemaNode, parent, generatableType, schema); + final JsonNode definitions = schemaNode.get("$defs"); + if (definitions != null && definitions.isObject()) { + final ObjectNode objectNode = (ObjectNode) definitions; + final Iterator nodeIterator = objectNode.fieldNames(); + while (nodeIterator.hasNext()) { + final String name = nodeIterator.next(); + try { + getSchemaRule() + .apply( + name, + (ObjectNode) objectNode.get(name), + schemaNode, + generatableType.getPackage(), + getSchemaStore() + .create( + schema, + "#/$defs/" + name, + getGenerationConfig().getRefFragmentPathDelimiters())); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + return result; + } + } +} diff --git a/diagram-rest/.gitignore b/diagram-rest/.gitignore deleted file mode 100644 index 0d809f8c..00000000 --- a/diagram-rest/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/** -!**/src/test/** - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ - -### VS Code ### -.vscode/ \ No newline at end of file diff --git a/diagram-rest/pom.xml b/diagram-rest/pom.xml deleted file mode 100644 index cbaafe2b..00000000 --- a/diagram-rest/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.7.6 - - - io.serverless - serverlessworkflow-diagram-rest - 5.0.0-SNAPSHOT - Serverless Workflow :: Diagram :: Rest API - Rest Api Module for Diagram Generation - - 1.6.13 - 5.0.0-SNAPSHOT - - - - org.springframework.boot - spring-boot-starter-webflux - - - io.serverlessworkflow - serverlessworkflow-diagram - ${version.sw} - - - org.springdoc - springdoc-openapi-webflux-core - ${version.webflux.core} - - - - - org.springframework.boot - spring-boot-starter-test - test - - - io.projectreactor - reactor-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/Application.java b/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/Application.java deleted file mode 100644 index 8965208c..00000000 --- a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/Application.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagramrest; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/DiagramRequest.java b/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/DiagramRequest.java deleted file mode 100644 index 09fa34b9..00000000 --- a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/DiagramRequest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagramrest; - -import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.server.ServerRequest; -import org.springframework.web.reactive.function.server.ServerResponse; -import reactor.core.publisher.Mono; - -@Component -public class DiagramRequest { - - /** - * Get the SVG diagram of a workflow from API Request - * - * @param sRequest workFlow (yml or json) - * @return String SVG - */ - public Mono getDiagramSVGFromWorkFlow(ServerRequest sRequest) { - return ServerResponse.ok() - .contentType(MediaType.APPLICATION_XML) - .body( - sRequest - .bodyToMono(String.class) - .flatMap(DiagramRequestHelper::getSvg) - .onErrorMap(e -> new IllegalArgumentException(e.getMessage())), - String.class); - } -} diff --git a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/DiagramRequestHelper.java b/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/DiagramRequestHelper.java deleted file mode 100644 index 8ae6a77d..00000000 --- a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/DiagramRequestHelper.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagramrest; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.WorkflowDiagram; -import io.serverlessworkflow.diagram.WorkflowDiagramImpl; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Mono; - -@Component -public class DiagramRequestHelper { - - public static Mono getSvg(String workFlow) { - String diagramSVG; - Workflow workflow = Workflow.fromSource(workFlow); - - WorkflowDiagram workflowDiagram = - new WorkflowDiagramImpl() - .showLegend(true) - .setWorkflow(workflow) - .setTemplate("custom-template"); - - try { - diagramSVG = workflowDiagram.getSvgDiagram(); - } catch (Exception e) { - return Mono.just(e.getMessage()); - } - return Mono.just(diagramSVG); - } -} diff --git a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/RouterRest.java b/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/RouterRest.java deleted file mode 100644 index e5e6e462..00000000 --- a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/RouterRest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagramrest; - -import static org.springframework.web.reactive.function.server.RequestPredicates.POST; -import static org.springframework.web.reactive.function.server.RouterFunctions.route; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.reactive.function.server.RouterFunction; -import org.springframework.web.reactive.function.server.ServerResponse; - -@Configuration -public class RouterRest implements RouterRestInterface { - @Bean - public RouterFunction diagramRouterFunction(DiagramRequest serverlessRequest) { - return route(POST("/diagram"), - serverlessRequest::getDiagramSVGFromWorkFlow); - } - -} diff --git a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/RouterRestInterface.java b/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/RouterRestInterface.java deleted file mode 100644 index 62ee3976..00000000 --- a/diagram-rest/src/main/java/io/serverlessworkflow/diagramrest/RouterRestInterface.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagramrest; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import org.springdoc.core.annotations.RouterOperation; -import org.springdoc.core.annotations.RouterOperations; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.reactive.function.server.RouterFunction; -import org.springframework.web.reactive.function.server.ServerResponse; - -public interface RouterRestInterface { - - @RouterOperations( - value = { - @RouterOperation( - path = "/diagram", - produces = {"application/xml"}, - method = RequestMethod.POST, - beanClass = DiagramRequest.class, - beanMethod = "getDiagramSVGFromWorkFlow", - operation = - @Operation( - operationId = "Get-Diagram-SVG-From-WorkFlow", - responses = { - @ApiResponse( - responseCode = "200", - description = "Get diagram SVG from workFlow", - content = - @Content( - schema = - @Schema(implementation = String.class))) - } - )) - }) - RouterFunction diagramRouterFunction(DiagramRequest serverlessRequest); - - -} diff --git a/diagram-rest/src/main/resources/application.yml b/diagram-rest/src/main/resources/application.yml deleted file mode 100644 index 8f13a949..00000000 --- a/diagram-rest/src/main/resources/application.yml +++ /dev/null @@ -1,12 +0,0 @@ -springdoc: - api-docs: - groups: - enable: true - path: "/api/serverless/v3/api-docs" - swagger-ui: - path: "/api/serverless/swagger-ui.html" -server: - port: 8090 -spring: - application: - name: "Serverless Workflow Diagram Rest API" \ No newline at end of file diff --git a/diagram-rest/src/main/resources/templates/plantuml/custom-template.txt b/diagram-rest/src/main/resources/templates/plantuml/custom-template.txt deleted file mode 100644 index e162afc5..00000000 --- a/diagram-rest/src/main/resources/templates/plantuml/custom-template.txt +++ /dev/null @@ -1,46 +0,0 @@ -@startuml -skinparam backgroundColor White -skinparam legendBackgroundColor White -skinparam legendBorderColor White -skinparam state { - StartColor Green - EndColor Orange - BackgroundColor GhostWhite - BackgroundColor<< workflow >> White - BorderColor Black - ArrowColor Black - - BorderColor<< event >> #7fe5f0 - BorderColor<< operation >> #bada55 - BorderColor<< switch >> #92a0f2 - BorderColor<< sleep >> #b83b5e - BorderColor<< parallel >> #6a2c70 - BorderColor<< inject >> #1e5f74 - BorderColor<< foreach >> #931a25 - BorderColor<< callback >> #ffcb8e -} -state "[(${diagram.title})]" as workflow << workflow >> { - -[# th:each="stateDef : ${diagram.modelStateDefs}" ] -[(${stateDef.toString()})] -[/] - -[# th:each="state : ${diagram.modelStates}" ] -[(${state.toString()})] -[/] - -[# th:each="connection : ${diagram.modelConnections}" ] -[(${connection.toString()})] -[/] - -} - -[# th:if="${diagram.showLegend}" ] -legend center -State Types and Border Colors: -| Event | Operation | Switch | Sleep | Parallel | Inject | ForEach | CallBack | -|<#7fe5f0>|<#bada55>|<#92a0f2>|<#b83b5e>|<#6a2c70>|<#1e5f74>|<#931a25>|| -endlegend -[/] - -@enduml \ No newline at end of file diff --git a/diagram-rest/src/test/java/io/serverlessworkflow/diagramrest/DiagramGenerationTest.java b/diagram-rest/src/test/java/io/serverlessworkflow/diagramrest/DiagramGenerationTest.java deleted file mode 100644 index 17041785..00000000 --- a/diagram-rest/src/test/java/io/serverlessworkflow/diagramrest/DiagramGenerationTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagramrest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import static org.junit.jupiter.api.Assertions.*; - -@ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = { - RouterRest.class, - DiagramRequest.class, - DiagramRequestHelper.class -}) -@WebFluxTest -class DiagramGenerationTest { - - private DiagramRequestHelper serverlesRequestHelper; - - public static final String input = "id: greeting\n" + - "version: '1.0'\n" + - "specVersion: '0.8'\n" + - "name: Greeting Workflow\n" + - "description: Greet Someone\n" + - "start: Greet\n" + - "functions:\n" + - " - name: greetingFunction\n" + - " operation: file://myapis/greetingapis.json#greeting\n" + - "states:\n" + - " - name: Greet\n" + - " type: operation\n" + - " actions:\n" + - " - functionRef:\n" + - " refName: greetingFunction\n" + - " arguments:\n" + - " name: \"${ .person.name }\"\n" + - " actionDataFilter:\n" + - " results: \"${ .greeting }\"\n" + - " end: true"; - - @BeforeEach - void setUp() { - serverlesRequestHelper = new DiagramRequestHelper(); - } - - @Test - void getSvg() { - Mono monoSvg = serverlesRequestHelper.getSvg(input); - monoSvg.subscribe(result -> { assertNotNull(result); assertNotNull(result);}); - StepVerifier.create(monoSvg) - .expectNextMatches(serverlessWorkFlowResponse -> serverlessWorkFlowResponse - .contains("svg")) - .verifyComplete(); - } -} \ No newline at end of file diff --git a/diagram/.gitignore b/diagram/.gitignore deleted file mode 100644 index d4dfde66..00000000 --- a/diagram/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/** -!**/src/test/** - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ - -### VS Code ### -.vscode/ \ No newline at end of file diff --git a/diagram/pom.xml b/diagram/pom.xml deleted file mode 100644 index 1b02de7e..00000000 --- a/diagram/pom.xml +++ /dev/null @@ -1,152 +0,0 @@ - - 4.0.0 - - - io.serverlessworkflow - serverlessworkflow-parent - 7.0.0-SNAPSHOT - - - serverlessworkflow-diagram - Serverless Workflow :: Diagram - jar - Diagram Generation - - - - org.slf4j - slf4j-api - - - - io.serverlessworkflow - serverlessworkflow-api - ${project.version} - - - - org.apache.commons - commons-lang3 - - - - org.thymeleaf - thymeleaf - - - net.sourceforge.plantuml - plantuml - - - guru.nidi - graphviz-java - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.jupiter - junit-jupiter-params - test - - - org.mockito - mockito-core - test - - - ch.qos.logback - logback-classic - test - - - org.assertj - assertj-core - test - - - org.hamcrest - hamcrest-library - test - - - org.skyscreamer - jsonassert - test - - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - - - - - - - - - - - - ${project.build.directory}/checkstyle.log - true - true - true - false - false - ${checkstyle.logViolationsToConsole} - ${checkstyle.failOnViolation} - - ${project.build.sourceDirectory} - ${project.build.testSourceDirectory} - - - - - compile - - check - - - - - - com.spotify.fmt - fmt-maven-plugin - - src/main/java - src/test/java - false - .*\.java - false - false - - - - - - format - - - - - - - \ No newline at end of file diff --git a/diagram/src/main/java/io/serverlessworkflow/diagram/WorkflowDiagramImpl.java b/diagram/src/main/java/io/serverlessworkflow/diagram/WorkflowDiagramImpl.java deleted file mode 100644 index 1fb5e656..00000000 --- a/diagram/src/main/java/io/serverlessworkflow/diagram/WorkflowDiagramImpl.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.WorkflowDiagram; -import io.serverlessworkflow.diagram.utils.WorkflowToPlantuml; -import java.io.ByteArrayOutputStream; -import java.nio.charset.Charset; -import net.sourceforge.plantuml.FileFormat; -import net.sourceforge.plantuml.FileFormatOption; -import net.sourceforge.plantuml.SourceStringReader; - -public class WorkflowDiagramImpl implements WorkflowDiagram { - - public static final String DEFAULT_TEMPLATE = "workflow-template"; - - @SuppressWarnings("unused") - private String source; - - @SuppressWarnings("unused") - private String template = DEFAULT_TEMPLATE; - - private Workflow workflow; - private boolean showLegend = false; - - @Override - public WorkflowDiagram setWorkflow(Workflow workflow) { - this.workflow = workflow; - this.source = Workflow.toJson(workflow); - return this; - } - - @Override - public WorkflowDiagram setSource(String source) { - this.source = source; - this.workflow = Workflow.fromSource(source); - return this; - } - - @Override - public WorkflowDiagram setTemplate(String template) { - this.template = template; - return this; - } - - @Override - public String getSvgDiagram() throws Exception { - if (workflow == null) { - throw new IllegalAccessException("Unable to get diagram - no workflow set."); - } - String diagramSource = WorkflowToPlantuml.convert(template, workflow, showLegend); - SourceStringReader reader = new SourceStringReader(diagramSource); - final ByteArrayOutputStream os = new ByteArrayOutputStream(); - reader.generateImage(os, new FileFormatOption(FileFormat.SVG)); - os.close(); - return new String(os.toByteArray(), Charset.forName("UTF-8")); - } - - @Override - public WorkflowDiagram showLegend(boolean showLegend) { - this.showLegend = showLegend; - return this; - } -} diff --git a/diagram/src/main/java/io/serverlessworkflow/diagram/config/ThymeleafConfig.java b/diagram/src/main/java/io/serverlessworkflow/diagram/config/ThymeleafConfig.java deleted file mode 100644 index 56c6b042..00000000 --- a/diagram/src/main/java/io/serverlessworkflow/diagram/config/ThymeleafConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.config; - -import org.thymeleaf.TemplateEngine; -import org.thymeleaf.templatemode.TemplateMode; -import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; -import org.thymeleaf.templateresolver.ITemplateResolver; - -public class ThymeleafConfig { - public static TemplateEngine templateEngine; - - static { - templateEngine = new TemplateEngine(); - templateEngine.addTemplateResolver(plantUmlTemplateResolver()); - } - - private static ITemplateResolver plantUmlTemplateResolver() { - ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver(); - templateResolver.setPrefix("/templates/plantuml/"); - templateResolver.setSuffix(".txt"); - templateResolver.setTemplateMode(TemplateMode.TEXT); - templateResolver.setCharacterEncoding("UTF8"); - templateResolver.setCheckExistence(true); - templateResolver.setCacheable(false); - return templateResolver; - } -} diff --git a/diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelConnection.java b/diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelConnection.java deleted file mode 100644 index 041e5521..00000000 --- a/diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelConnection.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.model; - -import io.serverlessworkflow.diagram.utils.WorkflowDiagramUtils; - -public class ModelConnection { - private String left; - private String right; - private String desc; - - public ModelConnection(String left, String right, String desc) { - this.left = left.replaceAll("\\s", ""); - this.right = right.replaceAll("\\s", ""); - this.desc = desc; - } - - @Override - public String toString() { - StringBuilder retBuff = new StringBuilder(); - retBuff.append(System.lineSeparator()); - retBuff.append( - left.equals(WorkflowDiagramUtils.wfStart) ? WorkflowDiagramUtils.startEnd : left); - retBuff.append(WorkflowDiagramUtils.connection); - retBuff.append( - right.equals(WorkflowDiagramUtils.wfEnd) ? WorkflowDiagramUtils.startEnd : right); - if (desc != null && desc.trim().length() > 0) { - retBuff.append(WorkflowDiagramUtils.description).append(desc); - } - retBuff.append(System.lineSeparator()); - - return retBuff.toString(); - } - - public String getLeft() { - return left; - } - - public void setLeft(String left) { - this.left = left; - } - - public String getRight() { - return right; - } - - public void setRight(String right) { - this.right = right; - } - - public String getDesc() { - return desc; - } - - public void setDesc(String desc) { - this.desc = desc; - } -} diff --git a/diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelState.java b/diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelState.java deleted file mode 100644 index 73c3cd0a..00000000 --- a/diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelState.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.model; - -import io.serverlessworkflow.diagram.utils.WorkflowDiagramUtils; -import java.util.ArrayList; -import java.util.List; - -public class ModelState { - - @SuppressWarnings("unused") - private String name; - - private String noSpaceName; - private List stateInfo = new ArrayList<>(); - - public ModelState(String name) { - this.name = name; - this.noSpaceName = name.replaceAll("\\s", ""); - } - - public void addInfo(String info) { - stateInfo.add(info); - } - - @Override - public String toString() { - StringBuilder retBuff = new StringBuilder(); - retBuff.append(System.lineSeparator()); - for (String info : stateInfo) { - retBuff - .append(noSpaceName) - .append(WorkflowDiagramUtils.description) - .append(info) - .append(System.lineSeparator()); - } - retBuff.append(System.lineSeparator()); - - return retBuff.toString(); - } -} diff --git a/diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelStateDef.java b/diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelStateDef.java deleted file mode 100644 index de258316..00000000 --- a/diagram/src/main/java/io/serverlessworkflow/diagram/model/ModelStateDef.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.model; - -import io.serverlessworkflow.diagram.utils.WorkflowDiagramUtils; - -public class ModelStateDef { - private String name; - private String type; - private String noSpaceName; - - public ModelStateDef(String name, String type) { - this.name = name; - this.type = type; - this.noSpaceName = name.replaceAll("\\s", ""); - } - - @Override - public String toString() { - StringBuilder retBuff = new StringBuilder(); - retBuff - .append(WorkflowDiagramUtils.stateDef) - .append(noSpaceName) - .append(WorkflowDiagramUtils.stateAsName) - .append("\"" + name + "\"") - .append(WorkflowDiagramUtils.typeDefStart) - .append(type) - .append(WorkflowDiagramUtils.typeDefEnd); - return retBuff.toString(); - } -} diff --git a/diagram/src/main/java/io/serverlessworkflow/diagram/model/WorkflowDiagramModel.java b/diagram/src/main/java/io/serverlessworkflow/diagram/model/WorkflowDiagramModel.java deleted file mode 100644 index f4050799..00000000 --- a/diagram/src/main/java/io/serverlessworkflow/diagram/model/WorkflowDiagramModel.java +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.model; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.states.*; -import io.serverlessworkflow.api.switchconditions.DataCondition; -import io.serverlessworkflow.api.switchconditions.EventCondition; -import io.serverlessworkflow.diagram.utils.WorkflowDiagramUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -public class WorkflowDiagramModel { - private Workflow workflow; - - private String title; - private String legend; - private String footer; - private List modelStateDefs = new ArrayList<>(); - private List modelStates = new ArrayList<>(); - private List modelConnections = new ArrayList<>(); - private boolean showLegend; - - public WorkflowDiagramModel(Workflow workflow, boolean showLegend) { - this.workflow = workflow; - this.showLegend = showLegend; - inspect(workflow); - } - - private void inspect(Workflow workflow) { - // title - setTitle(workflow.getName()); - if (workflow.getVersion() != null && workflow.getVersion().trim().length() > 0) { - StringBuilder titleBuf = - new StringBuilder() - .append(workflow.getName()) - .append(WorkflowDiagramUtils.versionSeparator) - .append(workflow.getVersion()); - setTitle(titleBuf.toString()); - } - - // legend - if (workflow.getDescription() != null && workflow.getDescription().trim().length() > 0) { - StringBuilder legendBuff = - new StringBuilder() - .append(WorkflowDiagramUtils.legendStart) - .append(workflow.getDescription()) - .append(WorkflowDiagramUtils.legendEnd); - setLegend(legendBuff.toString()); - } else { - setLegend(""); - } - - // footer - setFooter(WorkflowDiagramUtils.footer); - - // state definitions - inspectStateDefinitions(workflow); - - // states info - inspectStatesInfo(workflow); - - // states connections - inspectStatesConnections(workflow); - } - - private void inspectStateDefinitions(Workflow workflow) { - for (State state : workflow.getStates()) { - modelStateDefs.add(new ModelStateDef(state.getName(), state.getType().value())); - } - } - - private void inspectStatesConnections(Workflow workflow) { - State workflowStartState = WorkflowDiagramUtils.getWorkflowStartState(workflow); - modelConnections.add( - new ModelConnection(WorkflowDiagramUtils.wfStart, workflowStartState.getName(), "")); - - List workflowStates = workflow.getStates(); - for (State state : workflowStates) { - if (state instanceof SwitchState) { - SwitchState switchState = (SwitchState) state; - if (switchState.getDataConditions() != null && switchState.getDataConditions().size() > 0) { - for (DataCondition dataCondition : switchState.getDataConditions()) { - - if (dataCondition.getTransition() != null) { - if (dataCondition.getTransition().getProduceEvents() != null - && dataCondition.getTransition().getProduceEvents().size() > 0) { - List producedEvents = - dataCondition.getTransition().getProduceEvents().stream() - .map(t -> t.getEventRef()) - .collect(Collectors.toList()); - - String desc = ""; - if (dataCondition.getName() != null - && dataCondition.getName().trim().length() > 0) { - desc = dataCondition.getName(); - } - desc += - " Produced Events: " + producedEvents.stream().collect(Collectors.joining(",")); - modelConnections.add( - new ModelConnection( - switchState.getName(), dataCondition.getTransition().getNextState(), desc)); - } else { - String desc = ""; - if (dataCondition.getName() != null - && dataCondition.getName().trim().length() > 0) { - desc = dataCondition.getName(); - } - modelConnections.add( - new ModelConnection( - switchState.getName(), dataCondition.getTransition().getNextState(), desc)); - } - } - - if (dataCondition.getEnd() != null) { - if (dataCondition.getEnd().getProduceEvents() != null - && dataCondition.getEnd().getProduceEvents().size() > 0) { - List producedEvents = - dataCondition.getEnd().getProduceEvents().stream() - .map(t -> t.getEventRef()) - .collect(Collectors.toList()); - - String desc = ""; - if (dataCondition.getName() != null - && dataCondition.getName().trim().length() > 0) { - desc = dataCondition.getName(); - } - desc += - " Produced Events: " + producedEvents.stream().collect(Collectors.joining(",")); - modelConnections.add( - new ModelConnection(switchState.getName(), WorkflowDiagramUtils.wfEnd, desc)); - } else { - String desc = ""; - if (dataCondition.getName() != null - && dataCondition.getName().trim().length() > 0) { - desc = dataCondition.getName(); - } - modelConnections.add( - new ModelConnection(switchState.getName(), WorkflowDiagramUtils.wfEnd, desc)); - } - } - } - } - - if (switchState.getEventConditions() != null - && switchState.getEventConditions().size() > 0) { - for (EventCondition eventCondition : switchState.getEventConditions()) { - - if (eventCondition.getTransition() != null) { - if (eventCondition.getTransition().getProduceEvents() != null - && eventCondition.getTransition().getProduceEvents().size() > 0) { - List producedEvents = - eventCondition.getTransition().getProduceEvents().stream() - .map(t -> t.getEventRef()) - .collect(Collectors.toList()); - - String desc = ""; - if (eventCondition.getName() != null - && eventCondition.getName().trim().length() > 0) { - desc = eventCondition.getName(); - } - desc += - " Produced Events: " + producedEvents.stream().collect(Collectors.joining(",")); - modelConnections.add( - new ModelConnection( - switchState.getName(), - eventCondition.getTransition().getNextState(), - desc)); - } else { - String desc = ""; - if (eventCondition.getName() != null - && eventCondition.getName().trim().length() > 0) { - desc = eventCondition.getName(); - } - modelConnections.add( - new ModelConnection( - switchState.getName(), - eventCondition.getTransition().getNextState(), - desc)); - } - } - - if (eventCondition.getEnd() != null) { - if (eventCondition.getEnd().getProduceEvents() != null - && eventCondition.getEnd().getProduceEvents().size() > 0) { - List producedEvents = - eventCondition.getEnd().getProduceEvents().stream() - .map(t -> t.getEventRef()) - .collect(Collectors.toList()); - - String desc = ""; - if (eventCondition.getName() != null - && eventCondition.getName().trim().length() > 0) { - desc = eventCondition.getName(); - } - desc += - " Produced Events: " + producedEvents.stream().collect(Collectors.joining(",")); - modelConnections.add( - new ModelConnection(switchState.getName(), WorkflowDiagramUtils.wfEnd, desc)); - } else { - String desc = ""; - if (eventCondition.getName() != null - && eventCondition.getName().trim().length() > 0) { - desc = eventCondition.getName(); - } - modelConnections.add( - new ModelConnection(switchState.getName(), WorkflowDiagramUtils.wfEnd, desc)); - } - } - } - } - - // default - if (switchState.getDefaultCondition() != null) { - if (switchState.getDefaultCondition().getTransition() != null) { - if (switchState.getDefaultCondition().getTransition().getProduceEvents() != null - && switchState.getDefaultCondition().getTransition().getProduceEvents().size() - > 0) { - List producedEvents = - switchState.getDefaultCondition().getTransition().getProduceEvents().stream() - .map(t -> t.getEventRef()) - .collect(Collectors.toList()); - - String desc = "default - "; - desc += - " Produced Events: " + producedEvents.stream().collect(Collectors.joining(",")); - modelConnections.add( - new ModelConnection( - switchState.getName(), - switchState.getDefaultCondition().getTransition().getNextState(), - desc)); - } else { - String desc = "default"; - modelConnections.add( - new ModelConnection( - switchState.getName(), - switchState.getDefaultCondition().getTransition().getNextState(), - desc)); - } - } - - if (switchState.getDefaultCondition().getEnd() != null) { - if (switchState.getDefaultCondition().getEnd().getProduceEvents() != null - && switchState.getDefaultCondition().getEnd().getProduceEvents().size() > 0) { - List producedEvents = - switchState.getDefaultCondition().getEnd().getProduceEvents().stream() - .map(t -> t.getEventRef()) - .collect(Collectors.toList()); - - String desc = "default - "; - desc += - " Produced Events: " + producedEvents.stream().collect(Collectors.joining(",")); - modelConnections.add( - new ModelConnection(switchState.getName(), WorkflowDiagramUtils.wfEnd, desc)); - } else { - String desc = "default"; - modelConnections.add( - new ModelConnection(switchState.getName(), WorkflowDiagramUtils.wfEnd, desc)); - } - } - } - } else { - if (state.getTransition() != null) { - if (state.getTransition().getProduceEvents() != null - && state.getTransition().getProduceEvents().size() > 0) { - List producedEvents = - state.getTransition().getProduceEvents().stream() - .map(t -> t.getEventRef()) - .collect(Collectors.toList()); - - String desc = - "Produced Events: " + producedEvents.stream().collect(Collectors.joining(",")); - modelConnections.add( - new ModelConnection(state.getName(), state.getTransition().getNextState(), desc)); - } else { - modelConnections.add( - new ModelConnection(state.getName(), state.getTransition().getNextState(), "")); - } - } - - if (state.getEnd() != null) { - if (state.getEnd().getProduceEvents() != null - && state.getEnd().getProduceEvents().size() > 0) { - List producedEvents = - state.getEnd().getProduceEvents().stream() - .map(t -> t.getEventRef()) - .collect(Collectors.toList()); - - String desc = - "Produced Events: " + producedEvents.stream().collect(Collectors.joining(",")); - modelConnections.add( - new ModelConnection(state.getName(), WorkflowDiagramUtils.wfEnd, desc)); - } else { - modelConnections.add( - new ModelConnection(state.getName(), WorkflowDiagramUtils.wfEnd, "")); - } - } - } - } - } - - private void inspectStatesInfo(Workflow workflow) { - List workflowStates = workflow.getStates(); - for (State state : workflowStates) { - ModelState modelState = new ModelState(state.getName()); - - if (state instanceof EventState) { - EventState eventState = (EventState) state; - - List events = - eventState.getOnEvents().stream() - .flatMap(t -> t.getEventRefs().stream()) - .collect(Collectors.toList()); - - modelState.addInfo("Type: Event State"); - modelState.addInfo("Events: " + events.stream().collect(Collectors.joining(" "))); - } - - if (state instanceof OperationState) { - OperationState operationState = (OperationState) state; - - modelState.addInfo("Type: Operation State"); - modelState.addInfo( - "Action mode: " - + Optional.ofNullable(operationState.getActionMode()) - .orElse(OperationState.ActionMode.SEQUENTIAL)); - modelState.addInfo( - "Num. of actions: " - + Optional.ofNullable(operationState.getActions().size()).orElse(0)); - } - - if (state instanceof SwitchState) { - SwitchState switchState = (SwitchState) state; - - modelState.addInfo("Type: Switch State"); - if (switchState.getDataConditions() != null && switchState.getDataConditions().size() > 0) { - modelState.addInfo("Condition type: data-based"); - modelState.addInfo("Num. of conditions: " + switchState.getDataConditions().size()); - } - - if (switchState.getEventConditions() != null - && switchState.getEventConditions().size() > 0) { - modelState.addInfo("Condition type: event-based"); - modelState.addInfo("Num. of conditions: " + switchState.getEventConditions().size()); - } - - if (switchState.getDefaultCondition() != null) { - if (switchState.getDefaultCondition().getTransition() != null) { - modelState.addInfo( - "Default to: " + switchState.getDefaultCondition().getTransition().getNextState()); - } - - if (switchState.getDefaultCondition().getEnd() != null) { - modelState.addInfo("Default to: End"); - } - } - } - - if (state instanceof SleepState) { - SleepState sleepState = (SleepState) state; - - modelState.addInfo("Type: Sleep State"); - modelState.addInfo("Duration: " + sleepState.getDuration()); - } - - if (state instanceof ParallelState) { - ParallelState parallelState = (ParallelState) state; - - modelState.addInfo("Type: Parallel State"); - modelState.addInfo( - "Completion type: \"" + parallelState.getCompletionType().value() + "\""); - modelState.addInfo("Num. of branches: " + parallelState.getBranches().size()); - } - - if (state instanceof InjectState) { - modelState.addInfo("Type: Inject State"); - } - - if (state instanceof ForEachState) { - ForEachState forEachState = (ForEachState) state; - - modelState.addInfo("Type: ForEach State"); - modelState.addInfo("Input collection: " + forEachState.getInputCollection()); - if (forEachState.getActions() != null && forEachState.getActions().size() > 0) { - modelState.addInfo("Num. of actions: " + forEachState.getActions().size()); - } - } - - if (state instanceof CallbackState) { - CallbackState callbackState = (CallbackState) state; - - modelState.addInfo("Type: Callback State"); - modelState.addInfo( - "Callback function: " + callbackState.getAction().getFunctionRef().getRefName()); - modelState.addInfo("Callback event: " + callbackState.getEventRef()); - } - - modelStates.add(modelState); - } - } - - public Workflow getWorkflow() { - return workflow; - } - - public void setWorkflow(Workflow workflow) { - this.workflow = workflow; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getLegend() { - return legend; - } - - public void setLegend(String legend) { - this.legend = legend; - } - - public String getFooter() { - return footer; - } - - public void setFooter(String footer) { - this.footer = footer; - } - - public List getModelStates() { - return modelStates; - } - - public void setModelStates(List modelStates) { - this.modelStates = modelStates; - } - - public List getModelConnections() { - return modelConnections; - } - - public void setModelConnections(List modelConnections) { - this.modelConnections = modelConnections; - } - - public List getModelStateDefs() { - return modelStateDefs; - } - - public void setModelStateDefs(List modelStateDefs) { - this.modelStateDefs = modelStateDefs; - } - - public boolean getShowLegend() { - return showLegend; - } -} diff --git a/diagram/src/main/java/io/serverlessworkflow/diagram/utils/WorkflowDiagramUtils.java b/diagram/src/main/java/io/serverlessworkflow/diagram/utils/WorkflowDiagramUtils.java deleted file mode 100644 index 586d91db..00000000 --- a/diagram/src/main/java/io/serverlessworkflow/diagram/utils/WorkflowDiagramUtils.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.utils; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.states.DefaultState; -import java.util.List; -import java.util.stream.Collectors; - -public class WorkflowDiagramUtils { - public static final String versionSeparator = " v"; - public static final String wfStart = "wfstart"; - public static final String wfEnd = "wfend"; - public static final String startEnd = "[*]"; - public static final String connection = " --> "; - public static final String description = " : "; - public static final String title = "title "; - public static final String footer = - "center footer Serverless Workflow Specification - serverlessworkflow.io"; - public static final String legendStart = - new StringBuilder().append("legend top center").append(System.lineSeparator()).toString(); - public static final String legendEnd = - new StringBuilder().append(System.lineSeparator()).append("endlegend").toString(); - public static final String stateDef = "state "; - public static final String stateAsName = " as "; - public static final String typeDefStart = " << "; - public static final String typeDefEnd = " >> "; - - public static State getWorkflowStartState(Workflow workflow) { - return workflow.getStates().stream() - .filter(ws -> ws.getName().equals(workflow.getStart().getStateName())) - .findFirst() - .get(); - } - - public static List getStatesByType(Workflow workflow, DefaultState.Type type) { - return workflow.getStates().stream() - .filter(ws -> ws.getType() == type) - .collect(Collectors.toList()); - } - - public static List getWorkflowEndStates(Workflow workflow) { - return workflow.getStates().stream() - .filter(ws -> ws.getEnd() != null) - .collect(Collectors.toList()); - } -} diff --git a/diagram/src/main/java/io/serverlessworkflow/diagram/utils/WorkflowToPlantuml.java b/diagram/src/main/java/io/serverlessworkflow/diagram/utils/WorkflowToPlantuml.java deleted file mode 100644 index 956bcbeb..00000000 --- a/diagram/src/main/java/io/serverlessworkflow/diagram/utils/WorkflowToPlantuml.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.utils; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.diagram.config.ThymeleafConfig; -import io.serverlessworkflow.diagram.model.WorkflowDiagramModel; -import org.thymeleaf.TemplateEngine; -import org.thymeleaf.context.Context; - -public class WorkflowToPlantuml { - - public static String convert(String template, Workflow workflow, boolean showLegend) { - TemplateEngine plantUmlTemplateEngine = ThymeleafConfig.templateEngine; - Context context = new Context(); - context.setVariable("diagram", new WorkflowDiagramModel(workflow, showLegend)); - - return plantUmlTemplateEngine.process(template, context); - } -} diff --git a/diagram/src/main/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowDiagram b/diagram/src/main/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowDiagram deleted file mode 100644 index 637a614f..00000000 --- a/diagram/src/main/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowDiagram +++ /dev/null @@ -1 +0,0 @@ -io.serverlessworkflow.diagram.WorkflowDiagramImpl \ No newline at end of file diff --git a/diagram/src/main/resources/templates/plantuml/workflow-template.txt b/diagram/src/main/resources/templates/plantuml/workflow-template.txt deleted file mode 100644 index daf5fd6c..00000000 --- a/diagram/src/main/resources/templates/plantuml/workflow-template.txt +++ /dev/null @@ -1,46 +0,0 @@ -@startuml -skinparam backgroundColor White -skinparam legendBackgroundColor White -skinparam legendBorderColor White -skinparam state { - StartColor Green - EndColor Orange - BackgroundColor GhostWhite - BackgroundColor<< workflow >> White - BorderColor Black - ArrowColor Black - - BorderColor<< event >> #7fe5f0 - BorderColor<< operation >> #bada55 - BorderColor<< switch >> #92a0f2 - BorderColor<< sleep >> #b83b5e - BorderColor<< parallel >> #6a2c70 - BorderColor<< inject >> #1e5f74 - BorderColor<< foreach >> #931a25 - BorderColor<< callback >> #ffcb8e -} -state "[(${diagram.title})]" as workflow << workflow >> { - -[# th:each="stateDef : ${diagram.modelStateDefs}" ] -[(${stateDef.toString()})] -[/] - -[# th:each="state : ${diagram.modelStates}" ] -[(${state.toString()})] -[/] - -[# th:each="connection : ${diagram.modelConnections}" ] -[(${connection.toString()})] -[/] - -} - -[# th:if="${diagram.showLegend}" ] -legend center -State Types and Border Colors: -| Event | Operation | Switch | Sleep | Parallel | Inject | ForEach | CallBack | -|<#7fe5f0>|<#bada55>|<#92a0f2>|<#b83b5e>|<#6a2c70>|<#1e5f74>|<#931a25>|<#ffcb8e>| -endlegend -[/] - -@enduml \ No newline at end of file diff --git a/diagram/src/test/java/io/serverlessworkflow/diagram/test/CustomTemplateWorkflowDiagramTest.java b/diagram/src/test/java/io/serverlessworkflow/diagram/test/CustomTemplateWorkflowDiagramTest.java deleted file mode 100644 index 451ef265..00000000 --- a/diagram/src/test/java/io/serverlessworkflow/diagram/test/CustomTemplateWorkflowDiagramTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.test; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.WorkflowDiagram; -import io.serverlessworkflow.diagram.WorkflowDiagramImpl; -import io.serverlessworkflow.diagram.test.utils.DiagramTestUtils; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -public class CustomTemplateWorkflowDiagramTest { - - @ParameterizedTest - @ValueSource(strings = {"/examples/applicantrequest.json", "/examples/applicantrequest.yml"}) - public void testSpecExamplesParsing(String workflowLocation) throws Exception { - - Workflow workflow = Workflow.fromSource(DiagramTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - WorkflowDiagram workflowDiagram = - new WorkflowDiagramImpl() - .showLegend(true) - .setWorkflow(workflow) - .setTemplate("custom-template"); - - String diagramSVG = workflowDiagram.getSvgDiagram(); - Assertions.assertNotNull(diagramSVG); - // check custom template "customcolor" in the legend - Assertions.assertTrue(diagramSVG.contains("customcolor")); - } -} diff --git a/diagram/src/test/java/io/serverlessworkflow/diagram/test/WorkflowDiagramTest.java b/diagram/src/test/java/io/serverlessworkflow/diagram/test/WorkflowDiagramTest.java deleted file mode 100644 index 5251634b..00000000 --- a/diagram/src/test/java/io/serverlessworkflow/diagram/test/WorkflowDiagramTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.test; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.WorkflowDiagram; -import io.serverlessworkflow.diagram.WorkflowDiagramImpl; -import io.serverlessworkflow.diagram.test.utils.DiagramTestUtils; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -public class WorkflowDiagramTest { - - @ParameterizedTest - @ValueSource( - strings = { - "/examples/applicantrequest.json", - "/examples/applicantrequest.yml", - "/examples/carauctionbids.json", - "/examples/carauctionbids.yml", - "/examples/creditcheck.json", - "/examples/creditcheck.yml", - "/examples/eventbasedgreeting.json", - "/examples/eventbasedgreeting.yml", - "/examples/finalizecollegeapplication.json", - "/examples/finalizecollegeapplication.yml", - "/examples/greeting.json", - "/examples/greeting.yml", - "/examples/helloworld.json", - "/examples/helloworld.yml", - "/examples/jobmonitoring.json", - "/examples/jobmonitoring.yml", - "/examples/monitorpatient.json", - "/examples/monitorpatient.yml", - "/examples/parallel.json", - "/examples/parallel.yml", - "/examples/provisionorder.json", - "/examples/provisionorder.yml", - "/examples/sendcloudevent.json", - "/examples/sendcloudevent.yml", - "/examples/solvemathproblems.json", - "/examples/solvemathproblems.yml", - "/examples/foreachstatewithactions.json", - "/examples/foreachstatewithactions.yml", - "/examples/periodicinboxcheck.json", - "/examples/periodicinboxcheck.yml", - "/examples/vetappointmentservice.json", - "/examples/vetappointmentservice.yml", - "/examples/eventbasedtransition.json", - "/examples/eventbasedtransition.yml", - "/examples/roomreadings.json", - "/examples/roomreadings.yml", - "/examples/checkcarvitals.json", - "/examples/checkcarvitals.yml", - "/examples/booklending.json", - "/examples/booklending.yml" - }) - public void testSpecExamplesParsing(String workflowLocation) throws Exception { - - Workflow workflow = Workflow.fromSource(DiagramTestUtils.readWorkflowFile(workflowLocation)); - - assertNotNull(workflow); - assertNotNull(workflow.getId()); - assertNotNull(workflow.getName()); - assertNotNull(workflow.getStates()); - - WorkflowDiagram workflowDiagram = new WorkflowDiagramImpl(); - workflowDiagram.setWorkflow(workflow); - - String diagramSVG = workflowDiagram.getSvgDiagram(); - - Assertions.assertNotNull(diagramSVG); - } -} diff --git a/diagram/src/test/java/io/serverlessworkflow/diagram/test/utils/DiagramTestUtils.java b/diagram/src/test/java/io/serverlessworkflow/diagram/test/utils/DiagramTestUtils.java deleted file mode 100644 index 6365ba78..00000000 --- a/diagram/src/test/java/io/serverlessworkflow/diagram/test/utils/DiagramTestUtils.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.diagram.test.utils; - -import io.serverlessworkflow.api.mapper.JsonObjectMapper; -import io.serverlessworkflow.api.mapper.YamlObjectMapper; -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -public class DiagramTestUtils { - private static JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(); - private static YamlObjectMapper yamlObjectMapper = new YamlObjectMapper(); - - public static final Path resourceDirectory = Paths.get("src", "test", "resources"); - public static final String absolutePath = resourceDirectory.toFile().getAbsolutePath(); - - public static Path getResourcePath(String file) { - return Paths.get(absolutePath + File.separator + file); - } - - public static InputStream getInputStreamFromPath(Path path) throws Exception { - return Files.newInputStream(path); - } - - public static String readWorkflowFile(String location) { - return readFileAsString(classpathResourceReader(location)); - } - - public static Reader classpathResourceReader(String location) { - return new InputStreamReader(DiagramTestUtils.class.getResourceAsStream(location)); - } - - public static String readFileAsString(Reader reader) { - try { - StringBuilder fileData = new StringBuilder(1000); - char[] buf = new char[1024]; - int numRead; - while ((numRead = reader.read(buf)) != -1) { - String readData = String.valueOf(buf, 0, numRead); - fileData.append(readData); - buf = new char[1024]; - } - reader.close(); - return fileData.toString(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/diagram/src/test/resources/examples/applicantrequest.json b/diagram/src/test/resources/examples/applicantrequest.json deleted file mode 100644 index 1621c2bd..00000000 --- a/diagram/src/test/resources/examples/applicantrequest.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "id": "applicantrequest", - "version": "1.0", - "specVersion": "0.8", - "name": "Applicant Request Decision Workflow", - "description": "Determine if applicant request is valid", - "start": "CheckApplication", - "functions": [ - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/applicationapi.json#emailRejection" - } - ], - "states":[ - { - "name":"CheckApplication", - "type":"switch", - "dataConditions": [ - { - "condition": "${ .applicants | .age >= 18 }", - "transition": "StartApplication" - }, - { - "condition": "${ .applicants | .age < 18 }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "StartApplication", - "type": "operation", - "actions": [ - { - "subFlowRef": "startApplicationWorkflowId" - } - ], - "end": true - }, - { - "name":"RejectApplication", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .applicant }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/applicantrequest.yml b/diagram/src/test/resources/examples/applicantrequest.yml deleted file mode 100644 index ae0db1be..00000000 --- a/diagram/src/test/resources/examples/applicantrequest.yml +++ /dev/null @@ -1,33 +0,0 @@ -id: applicantrequest -version: '1.0' -specVersion: '0.8' -name: Applicant Request Decision Workflow -description: Determine if applicant request is valid -start: CheckApplication -functions: - - name: sendRejectionEmailFunction - operation: http://myapis.org/applicationapi.json#emailRejection -states: - - name: CheckApplication - type: switch - dataConditions: - - condition: "${ .applicants | .age >= 18 }" - transition: StartApplication - - condition: "${ .applicants | .age < 18 }" - transition: RejectApplication - defaultCondition: - transition: RejectApplication - - name: StartApplication - type: operation - actions: - - subFlowRef: startApplicationWorkflowId - end: true - - name: RejectApplication - type: operation - actionMode: sequential - actions: - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .applicant }" - end: true diff --git a/diagram/src/test/resources/examples/booklending.json b/diagram/src/test/resources/examples/booklending.json deleted file mode 100644 index faad4ea5..00000000 --- a/diagram/src/test/resources/examples/booklending.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "id": "booklending", - "name": "Book Lending Workflow", - "version": "1.0", - "specVersion": "0.8", - "start": "Book Lending Request", - "states": [ - { - "name": "Book Lending Request", - "type": "event", - "onEvents": [ - { - "eventRefs": ["Book Lending Request Event"] - } - ], - "transition": "Get Book Status" - }, - { - "name": "Get Book Status", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "Get status for book", - "arguments": { - "bookid": "${ .book.id }" - } - } - } - ], - "transition": "Book Status Decision" - }, - { - "name": "Book Status Decision", - "type": "switch", - "dataConditions": [ - { - "name": "Book is on loan", - "condition": "${ .book.status == \"onloan\" }", - "transition": "Report Status To Lender" - }, - { - "name": "Check is available", - "condition": "${ .book.status == \"available\" }", - "transition": "Check Out Book" - } - ] - }, - { - "name": "Report Status To Lender", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "Send status to lender", - "arguments": { - "bookid": "${ .book.id }", - "message": "Book ${ .book.title } is already on loan" - } - } - } - ], - "transition": "Wait for Lender response" - }, - { - "name": "Wait for Lender response", - "type": "switch", - "eventConditions": [ - { - "name": "Hold Book", - "eventRef": "Hold Book Event", - "transition": "Request Hold" - }, - { - "name": "Decline Book Hold", - "eventRef": "Decline Hold Event", - "transition": "Cancel Request" - } - ] - }, - { - "name": "Request Hold", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "Request hold for lender", - "arguments": { - "bookid": "${ .book.id }", - "lender": "${ .lender }" - } - } - } - ], - "transition": "Wait two weeks" - }, - { - "name": "Wait two weeks", - "type": "sleep", - "duration": "P2W", - "transition": "Get Book Status" - }, - { - "name": "Check Out Book", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "Check out book with id", - "arguments": { - "bookid": "${ .book.id }" - } - } - }, - { - "functionRef": { - "refName": "Notify Lender for checkout", - "arguments": { - "bookid": "${ .book.id }", - "lender": "${ .lender }" - } - } - } - ], - "end": true - } - ], - "functions": [], - "events": [] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/booklending.yml b/diagram/src/test/resources/examples/booklending.yml deleted file mode 100644 index 57903c07..00000000 --- a/diagram/src/test/resources/examples/booklending.yml +++ /dev/null @@ -1,75 +0,0 @@ -id: booklending -name: Book Lending Workflow -version: '1.0' -specVersion: '0.8' -start: Book Lending Request -states: - - name: Book Lending Request - type: event - onEvents: - - eventRefs: - - Book Lending Request Event - transition: Get Book Status - - name: Get Book Status - type: operation - actions: - - functionRef: - refName: Get status for book - arguments: - bookid: "${ .book.id }" - transition: Book Status Decision - - name: Book Status Decision - type: switch - dataConditions: - - name: Book is on loan - condition: ${ .book.status == "onloan" } - transition: Report Status To Lender - - name: Check is available - condition: ${ .book.status == "available" } - transition: Check Out Book - - name: Report Status To Lender - type: operation - actions: - - functionRef: - refName: Send status to lender - arguments: - bookid: "${ .book.id }" - message: Book ${ .book.title } is already on loan - transition: Wait for Lender response - - name: Wait for Lender response - type: switch - eventConditions: - - name: Hold Book - eventRef: Hold Book Event - transition: Request Hold - - name: Decline Book Hold - eventRef: Decline Hold Event - transition: Cancel Request - - name: Request Hold - type: operation - actions: - - functionRef: - refName: Request fold for lender - arguments: - bookid: "${ .book.id }" - lender: "${ .lender }" - transition: Wait two weeks - - name: Wait two weeks - type: sleep - duration: P2W - transition: Get Book Status - - name: Check Out Book - type: operation - actions: - - functionRef: - refName: Check out book with id - arguments: - bookid: "${ .book.id }" - - functionRef: - refName: Notify Lender for checkout - arguments: - bookid: "${ .book.id }" - lender: "${ .lender }" - end: true -functions: -events: \ No newline at end of file diff --git a/diagram/src/test/resources/examples/carauctionbids.json b/diagram/src/test/resources/examples/carauctionbids.json deleted file mode 100644 index 7ea84d9a..00000000 --- a/diagram/src/test/resources/examples/carauctionbids.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "id": "handleCarAuctionBid", - "version": "1.0", - "specVersion": "0.8", - "name": "Car Auction Bidding Workflow", - "description": "Store a single bid whole the car auction is active", - "start": { - "stateName": "StoreCarAuctionBid", - "schedule": "2020-03-20T09:00:00Z/2020-03-20T15:00:00Z" - }, - "functions": [ - { - "name": "StoreBidFunction", - "operation": "http://myapis.org/carauctionapi.json#storeBid" - } - ], - "events": [ - { - "name": "CarBidEvent", - "type": "carBidMadeType", - "source": "carBidEventSource" - } - ], - "states": [ - { - "name": "StoreCarAuctionBid", - "type": "event", - "exclusive": true, - "onEvents": [ - { - "eventRefs": ["CarBidEvent"], - "actions": [{ - "functionRef": { - "refName": "StoreBidFunction", - "arguments": { - "bid": "${ .bid }" - } - } - }] - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/carauctionbids.yml b/diagram/src/test/resources/examples/carauctionbids.yml deleted file mode 100644 index adfe0d08..00000000 --- a/diagram/src/test/resources/examples/carauctionbids.yml +++ /dev/null @@ -1,28 +0,0 @@ -id: handleCarAuctionBid -version: '1.0' -specVersion: '0.8' -name: Car Auction Bidding Workflow -description: Store a single bid whole the car auction is active -start: - stateName: StoreCarAuctionBid - schedule: 2020-03-20T09:00:00Z/2020-03-20T15:00:00Z -functions: - - name: StoreBidFunction - operation: http://myapis.org/carauctionapi.json#storeBid -events: - - name: CarBidEvent - type: carBidMadeType - source: carBidEventSource -states: - - name: StoreCarAuctionBid - type: event - exclusive: true - onEvents: - - eventRefs: - - CarBidEvent - actions: - - functionRef: - refName: StoreBidFunction - arguments: - bid: "${ .bid }" - end: true \ No newline at end of file diff --git a/diagram/src/test/resources/examples/checkcarvitals.json b/diagram/src/test/resources/examples/checkcarvitals.json deleted file mode 100644 index 973153fc..00000000 --- a/diagram/src/test/resources/examples/checkcarvitals.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "id": "vitalscheck", - "name": "Car Vitals Check", - "version": "1.0", - "specVersion": "0.8", - "start": "CheckVitals", - "states": [ - { - "name": "CheckVitals", - "type": "operation", - "actions": [ - { - "functionRef": "checkTirePressure" - }, - { - "functionRef": "checkOilPressure" - }, - { - "functionRef": "checkCoolantLevel" - }, - { - "functionRef": "checkBattery" - } - ], - "transition": "EvaluateChecks" - }, - { - "name": "EvaluateChecks", - "type": "switch", - "dataConditions": [ - { - "name": "Some Evaluations failed", - "condition": ".evaluations[?(@.check == 'failed')]", - "end": { - "produceEvents": [ - { - "eventRef": "DisplayFailedChecksOnDashboard", - "data": "${ .evaluations }" - } - ] - - } - } - ], - "defaultCondition": { - "transition": "WaitTwoMinutes" - } - }, - { - "name": "WaitTwoMinutes", - "type": "event", - "onEvents": [ - { - "eventRefs": ["StopVitalsCheck"], - "eventDataFilter": { - "toStateData": "${ .stopReceived }" - } - } - ], - "timeouts": { - "eventTimeout": "PT2M" - }, - "transition": "ShouldStopOrContinue" - }, - { - "name": "ShouldStopOrContinue", - "type": "switch", - "dataConditions": [ - { - "name": "Stop Event Received", - "condition": "${ has(\"stopReceived\") }", - "end": { - "produceEvents": [ - { - "eventRef": "VitalsCheckingStopped" - } - ] - - } - } - ], - "defaultCondition": { - "transition": "CheckVitals" - } - } - ], - "events": [ - { - "name": "StopVitalsCheck", - "type": "car.events", - "source": "my/car" - }, - { - "name": "VitalsCheckingStopped", - "type": "car.events", - "source": "my/car" - }, - { - "name": "DisplayFailedChecksOnDashboard", - "kind": "produced", - "type": "my.car.events" - } - ], - "functions": [ - { - "name": "checkTirePressure", - "operation": "mycarservices.json#checktirepressure" - }, - { - "name": "checkOilPressure", - "operation": "mycarservices.json#checkoilpressure" - }, - { - "name": "checkCoolantLevel", - "operation": "mycarservices.json#checkcoolantlevel" - }, - { - "name": "checkBattery", - "operation": "mycarservices.json#checkbattery" - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/checkcarvitals.yml b/diagram/src/test/resources/examples/checkcarvitals.yml deleted file mode 100644 index 31bd571a..00000000 --- a/diagram/src/test/resources/examples/checkcarvitals.yml +++ /dev/null @@ -1,64 +0,0 @@ -id: vitalscheck -name: Car Vitals Check -version: '1.0' -specVersion: '0.8' -start: CheckVitals -states: - - name: CheckVitals - type: operation - actions: - - functionRef: checkTirePressure - - functionRef: checkOilPressure - - functionRef: checkCoolantLevel - - functionRef: checkBattery - transition: EvaluateChecks - - name: EvaluateChecks - type: switch - dataConditions: - - name: Some Evaluations failed - condition: ".evaluations[?(@.check == 'failed')]" - end: - produceEvents: - - eventRef: DisplayFailedChecksOnDashboard - data: "${ .evaluations }" - defaultCondition: - transition: WaitTwoMinutes - - name: WaitTwoMinutes - type: event - onEvents: - - eventRefs: - - StopVitalsCheck - eventDataFilter: - toStateData: "${ .stopReceived }" - timeouts: - eventTimeout: PT2M - transition: ShouldStopOrContinue - - name: ShouldStopOrContinue - type: switch - dataConditions: - - name: Stop Event Received - condition: ${ has("stopReceived") } - end: - produceEvents: - - eventRef: VitalsCheckingStopped - defaultCondition: - transition: CheckVitals -events: - - name: StopVitalsCheck - type: car.events - source: my/car - - name: VitalsCheckingStopped - type: car.events - source: my/car - - name: DisplayFailedChecksOnDashboard - kind: produced - type: my.car.events -functions: - - name: checkTirePressure - operation: mycarservices.json#checktirepressure - - name: checkOilPressure - operation: mycarservices.json#checkoilpressure - - name: checkCoolantLevel - operation: mycarservices.json#checkcoolantlevel - - name: checkBattery - operation: mycarservices.json#checkbattery diff --git a/diagram/src/test/resources/examples/creditcheck.json b/diagram/src/test/resources/examples/creditcheck.json deleted file mode 100644 index 466d2eb7..00000000 --- a/diagram/src/test/resources/examples/creditcheck.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "id": "customercreditcheck", - "version": "1.0", - "specVersion": "0.8", - "name": "Customer Credit Check Workflow", - "description": "Perform Customer Credit Check", - "start": "CheckCredit", - "functions": [ - { - "name": "creditCheckFunction", - "operation": "http://myapis.org/creditcheckapi.json#doCreditCheck" - }, - { - "name": "sendRejectionEmailFunction", - "operation": "http://myapis.org/creditcheckapi.json#rejectionEmail" - } - ], - "events": [ - { - "name": "CreditCheckCompletedEvent", - "type": "creditCheckCompleteType", - "source": "creditCheckSource", - "correlation": [ - { - "contextAttributeName": "customerId" - } - ] - } - ], - "states": [ - { - "name": "CheckCredit", - "type": "callback", - "action": { - "functionRef": { - "refName": "callCreditCheckMicroservice", - "arguments": { - "customer": "${ .customer }" - } - } - }, - "eventRef": "CreditCheckCompletedEvent", - "timeouts": { - "stateExecTimeout": "PT15M" - }, - "transition": "EvaluateDecision" - }, - { - "name": "EvaluateDecision", - "type": "switch", - "dataConditions": [ - { - "condition": "${ .creditCheck | .decision == \"Approved\" }", - "transition": "StartApplication" - }, - { - "condition": "${ .creditCheck | .decision == \"Denied\" }", - "transition": "RejectApplication" - } - ], - "defaultCondition": { - "transition": "RejectApplication" - } - }, - { - "name": "StartApplication", - "type": "operation", - "actions": [ - { - "subFlowRef": "startApplicationWorkflowId" - } - ], - "end": true - }, - { - "name": "RejectApplication", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": { - "refName": "sendRejectionEmailFunction", - "arguments": { - "applicant": "${ .customer }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/creditcheck.yml b/diagram/src/test/resources/examples/creditcheck.yml deleted file mode 100644 index 8831ada7..00000000 --- a/diagram/src/test/resources/examples/creditcheck.yml +++ /dev/null @@ -1,52 +0,0 @@ -id: customercreditcheck -version: '1.0' -specVersion: '0.8' -name: Customer Credit Check Workflow -description: Perform Customer Credit Check -start: CheckCredit -functions: - - name: creditCheckFunction - operation: http://myapis.org/creditcheckapi.json#doCreditCheck - - name: sendRejectionEmailFunction - operation: http://myapis.org/creditcheckapi.json#rejectionEmail -events: - - name: CreditCheckCompletedEvent - type: creditCheckCompleteType - source: creditCheckSource - correlation: - - contextAttributeName: customerId -states: - - name: CheckCredit - type: callback - action: - functionRef: - refName: callCreditCheckMicroservice - arguments: - customer: "${ .customer }" - eventRef: CreditCheckCompletedEvent - timeouts: - stateExecTimeout: PT15M - transition: EvaluateDecision - - name: EvaluateDecision - type: switch - dataConditions: - - condition: ${ .creditCheck | .decision == "Approved" } - transition: StartApplication - - condition: ${ .creditCheck | .decision == "Denied" } - transition: RejectApplication - defaultCondition: - transition: RejectApplication - - name: StartApplication - type: operation - actions: - - subFlowRef: startApplicationWorkflowId - end: true - - name: RejectApplication - type: operation - actionMode: sequential - actions: - - functionRef: - refName: sendRejectionEmailFunction - arguments: - applicant: "${ .customer }" - end: true diff --git a/diagram/src/test/resources/examples/eventbasedgreeting.json b/diagram/src/test/resources/examples/eventbasedgreeting.json deleted file mode 100644 index efdc2c92..00000000 --- a/diagram/src/test/resources/examples/eventbasedgreeting.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "id": "eventbasedgreeting", - "version": "1.0", - "specVersion": "0.8", - "name": "Event Based Greeting Workflow", - "description": "Event Based Greeting", - "start": "Greet", - "events": [ - { - "name": "GreetingEvent", - "type": "greetingEventType", - "source": "greetingEventSource" - } - ], - "functions": [ - { - "name": "greetingFunction", - "operation": "file://myapis/greetingapis.json#greeting" - } - ], - "states":[ - { - "name":"Greet", - "type":"event", - "onEvents": [{ - "eventRefs": ["GreetingEvent"], - "eventDataFilter": { - "data": "${ .data.greet }" - }, - "actions":[ - { - "functionRef": { - "refName": "greetingFunction", - "arguments": { - "name": "${ .greet.name }" - } - } - } - ] - }], - "stateDataFilter": { - "output": "${ .payload.greeting }" - }, - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/eventbasedgreeting.yml b/diagram/src/test/resources/examples/eventbasedgreeting.yml deleted file mode 100644 index c18b61fe..00000000 --- a/diagram/src/test/resources/examples/eventbasedgreeting.yml +++ /dev/null @@ -1,29 +0,0 @@ -id: eventbasedgreeting -version: '1.0' -specVersion: '0.8' -name: Event Based Greeting Workflow -description: Event Based Greeting -start: Greet -events: - - name: GreetingEvent - type: greetingEventType - source: greetingEventSource -functions: - - name: greetingFunction - operation: file://myapis/greetingapis.json#greeting -states: - - name: Greet - type: event - onEvents: - - eventRefs: - - GreetingEvent - eventDataFilter: - data: "${ .data.greet }" - actions: - - functionRef: - refName: greetingFunction - arguments: - name: "${ .greet.name }" - stateDataFilter: - output: "${ .payload.greeting }" - end: true \ No newline at end of file diff --git a/diagram/src/test/resources/examples/eventbasedtransition.json b/diagram/src/test/resources/examples/eventbasedtransition.json deleted file mode 100644 index da0b8d6e..00000000 --- a/diagram/src/test/resources/examples/eventbasedtransition.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "id": "eventbasedswitch", - "version": "1.0", - "specVersion": "0.8", - "name": "Event Based Switch Transitions", - "description": "Event Based Switch Transitions", - "start": "CheckVisaStatus", - "events": [ - { - "name": "visaApprovedEvent", - "type": "VisaApproved", - "source": "visaCheckSource" - }, - { - "name": "visaRejectedEvent", - "type": "VisaRejected", - "source": "visaCheckSource" - } - ], - "states":[ - { - "name":"CheckVisaStatus", - "type":"switch", - "eventConditions": [ - { - "eventRef": "visaApprovedEvent", - "transition": "HandleApprovedVisa" - }, - { - "eventRef": "visaRejectedEvent", - "transition": "HandleRejectedVisa" - } - ], - "timeouts": { - "eventTimeout": "PT1H" - }, - "defaultCondition": { - "transition": "HandleNoVisaDecision" - } - }, - { - "name": "HandleApprovedVisa", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleApprovedVisaWorkflowID" - } - ], - "end": true - }, - { - "name": "HandleRejectedVisa", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleRejectedVisaWorkflowID" - } - ], - "end": true - }, - { - "name": "HandleNoVisaDecision", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleNoVisaDecisionWorkflowId" - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/eventbasedtransition.yml b/diagram/src/test/resources/examples/eventbasedtransition.yml deleted file mode 100644 index bb1203a1..00000000 --- a/diagram/src/test/resources/examples/eventbasedtransition.yml +++ /dev/null @@ -1,40 +0,0 @@ -id: eventbasedswitch -version: '1.0' -specVersion: '0.8' -name: Event Based Switch Transitions -description: Event Based Switch Transitions -start: CheckVisaStatus -events: - - name: visaApprovedEvent - type: VisaApproved - source: visaCheckSource - - name: visaRejectedEvent - type: VisaRejected - source: visaCheckSource -states: - - name: CheckVisaStatus - type: switch - eventConditions: - - eventRef: visaApprovedEvent - transition: HandleApprovedVisa - - eventRef: visaRejectedEvent - transition: HandleRejectedVisa - timeouts: - eventTimeout: PT1H - defaultCondition: - transition: HandleNoVisaDecision - - name: HandleApprovedVisa - type: operation - actions: - - subFlowRef: handleApprovedVisaWorkflowID - end: true - - name: HandleRejectedVisa - type: operation - actions: - - subFlowRef: handleRejectedVisaWorkflowID - end: true - - name: HandleNoVisaDecision - type: operation - actions: - - subFlowRef: handleNoVisaDecisionWorkflowId - end: true diff --git a/diagram/src/test/resources/examples/finalizecollegeapplication.json b/diagram/src/test/resources/examples/finalizecollegeapplication.json deleted file mode 100644 index 8fcb7670..00000000 --- a/diagram/src/test/resources/examples/finalizecollegeapplication.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "id": "finalizeCollegeApplication", - "name": "Finalize College Application", - "version": "1.0", - "specVersion": "0.8", - "start": "FinalizeApplication", - "events": [ - { - "name": "ApplicationSubmitted", - "type": "org.application.submitted", - "source": "applicationsource", - "correlation": [ - { - "contextAttributeName": "applicantId" - } - ] - }, - { - "name": "SATScoresReceived", - "type": "org.application.satscores", - "source": "applicationsource", - "correlation": [ - { - "contextAttributeName": "applicantId" - } - ] - }, - { - "name": "RecommendationLetterReceived", - "type": "org.application.recommendationLetter", - "source": "applicationsource", - "correlation": [ - { - "contextAttributeName": "applicantId" - } - ] - } - ], - "functions": [ - { - "name": "finalizeApplicationFunction", - "operation": "http://myapis.org/collegeapplicationapi.json#finalize" - } - ], - "states": [ - { - "name": "FinalizeApplication", - "type": "event", - "exclusive": false, - "onEvents": [ - { - "eventRefs": [ - "ApplicationSubmitted", - "SATScoresReceived", - "RecommendationLetterReceived" - ], - "actions": [ - { - "functionRef": { - "refName": "finalizeApplicationFunction", - "arguments": { - "student": "${ .applicantId }" - } - } - } - ] - } - ], - "end": { - "terminate": true - } - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/finalizecollegeapplication.yml b/diagram/src/test/resources/examples/finalizecollegeapplication.yml deleted file mode 100644 index 0d2fd30c..00000000 --- a/diagram/src/test/resources/examples/finalizecollegeapplication.yml +++ /dev/null @@ -1,40 +0,0 @@ -id: finalizeCollegeApplication -name: Finalize College Application -version: '1.0' -specVersion: '0.8' -start: FinalizeApplication -events: - - name: ApplicationSubmitted - type: org.application.submitted - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: SATScoresReceived - type: org.application.satscores - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: RecommendationLetterReceived - type: org.application.recommendationLetter - source: applicationsource - correlation: - - contextAttributeName: applicantId -functions: - - name: finalizeApplicationFunction - operation: http://myapis.org/collegeapplicationapi.json#finalize -states: - - name: FinalizeApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true \ No newline at end of file diff --git a/diagram/src/test/resources/examples/foreachstatewithactions.json b/diagram/src/test/resources/examples/foreachstatewithactions.json deleted file mode 100644 index d312e3ac..00000000 --- a/diagram/src/test/resources/examples/foreachstatewithactions.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "id": "foreachstatewithactions", - "name": "ForEach State With Actions", - "description": "ForEach State With Actions", - "version": "1.0", - "specVersion": "0.8", - "start": "SendConfirmationForEachCompletedhOrder", - "functions": [ - { - "name": "sendConfirmationFunction", - "operation": "http://myapis.org/confirmationapi.json#sendConfirmation" - } - ], - "states": [ - { - "name":"SendConfirmationForEachCompletedhOrder", - "type":"foreach", - "inputCollection": "${ .orders[?(@.completed == true)] }", - "iterationParam": "${ .completedorder }", - "actions":[ - { - "functionRef": { - "refName": "sendConfirmationFunction", - "arguments": { - "orderNumber": "${ .completedorder.orderNumber }", - "email": "${ .completedorder.email }" - } - } - }], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/foreachstatewithactions.yml b/diagram/src/test/resources/examples/foreachstatewithactions.yml deleted file mode 100644 index e3f5ed29..00000000 --- a/diagram/src/test/resources/examples/foreachstatewithactions.yml +++ /dev/null @@ -1,21 +0,0 @@ -id: foreachstatewithactions -name: ForEach State With Actions -description: ForEach State With Actions -version: '1.0' -specVersion: '0.8' -start: SendConfirmationForEachCompletedhOrder -functions: - - name: sendConfirmationFunction - operation: http://myapis.org/confirmationapi.json#sendConfirmation -states: - - name: SendConfirmationForEachCompletedhOrder - type: foreach - inputCollection: "${ .orders[?(@.completed == true)] }" - iterationParam: "${ .completedorder }" - actions: - - functionRef: - refName: sendConfirmationFunction - arguments: - orderNumber: "${ .completedorder.orderNumber }" - email: "${ .completedorder.email }" - end: true diff --git a/diagram/src/test/resources/examples/greeting.json b/diagram/src/test/resources/examples/greeting.json deleted file mode 100644 index f9138d90..00000000 --- a/diagram/src/test/resources/examples/greeting.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": "greeting", - "version": "1.0", - "specVersion": "0.8", - "name": "Greeting Workflow", - "description": "Greet Someone", - "start": "Greet", - "functions": [ - { - "name": "greetingFunction", - "operation": "file://myapis/greetingapis.json#greeting" - } - ], - "states":[ - { - "name":"Greet", - "type":"operation", - "actions":[ - { - "functionRef": { - "refName": "greetingFunction", - "arguments": { - "name": "${ .person.name }" - } - }, - "actionDataFilter": { - "results": "${ .greeting }" - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/greeting.yml b/diagram/src/test/resources/examples/greeting.yml deleted file mode 100644 index ceb14ae0..00000000 --- a/diagram/src/test/resources/examples/greeting.yml +++ /dev/null @@ -1,20 +0,0 @@ -id: greeting -version: '1.0' -specVersion: '0.8' -name: Greeting Workflow -description: Greet Someone -start: Greet -functions: - - name: greetingFunction - operation: file://myapis/greetingapis.json#greeting -states: - - name: Greet - type: operation - actions: - - functionRef: - refName: greetingFunction - arguments: - name: "${ .person.name }" - actionDataFilter: - results: "${ .greeting }" - end: true \ No newline at end of file diff --git a/diagram/src/test/resources/examples/helloworld.json b/diagram/src/test/resources/examples/helloworld.json deleted file mode 100644 index c8d48ca8..00000000 --- a/diagram/src/test/resources/examples/helloworld.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "id": "helloworld", - "version": "1.0", - "specVersion": "0.8", - "name": "Hello World Workflow", - "description": "Inject Hello World", - "start": "Hello State", - "states":[ - { - "name":"Hello State", - "type":"inject", - "data": { - "result": "Hello World!" - }, - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/helloworld.yml b/diagram/src/test/resources/examples/helloworld.yml deleted file mode 100644 index 32a84296..00000000 --- a/diagram/src/test/resources/examples/helloworld.yml +++ /dev/null @@ -1,12 +0,0 @@ -id: helloworld -version: '1.0' -specVersion: '0.8' -name: Hello World Workflow -description: Inject Hello World -start: Hello State -states: - - name: Hello State - type: inject - data: - result: Hello World! - end: true \ No newline at end of file diff --git a/diagram/src/test/resources/examples/jobmonitoring.json b/diagram/src/test/resources/examples/jobmonitoring.json deleted file mode 100644 index 8b0b8e9c..00000000 --- a/diagram/src/test/resources/examples/jobmonitoring.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "id": "jobmonitoring", - "version": "1.0", - "specVersion": "0.8", - "name": "Job Monitoring", - "description": "Monitor finished execution of a submitted job", - "start": "SubmitJob", - "functions": [ - { - "name": "submitJob", - "operation": "http://myapis.org/monitorapi.json#doSubmit" - }, - { - "name": "checkJobStatus", - "operation": "http://myapis.org/monitorapi.json#checkStatus" - }, - { - "name": "reportJobSuceeded", - "operation": "http://myapis.org/monitorapi.json#reportSucceeded" - }, - { - "name": "reportJobFailed", - "operation": "http://myapis.org/monitorapi.json#reportFailure" - } - ], - "states":[ - { - "name":"SubmitJob", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "submitJob", - "arguments": { - "name": "${ .job.name }" - } - }, - "actionDataFilter": { - "results": "${ .jobuid }" - } - } - ], - "onErrors": [ - { - "errorRef": "AllErrors", - "transition": "SubmitError" - } - ], - "stateDataFilter": { - "output": "${ .jobuid }" - }, - "transition": "WaitForCompletion" - }, - { - "name": "SubmitError", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleJobSubmissionErrorWorkflow" - } - ], - "end": true - }, - { - "name": "WaitForCompletion", - "type": "sleep", - "duration": "PT5S", - "transition": "GetJobStatus" - }, - { - "name":"GetJobStatus", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "checkJobStatus", - "arguments": { - "name": "${ .jobuid }" - } - }, - "actionDataFilter": { - "results": "${ .jobstatus }" - } - } - ], - "stateDataFilter": { - "output": "${ .jobstatus }" - }, - "transition": "DetermineCompletion" - }, - { - "name":"DetermineCompletion", - "type":"switch", - "dataConditions": [ - { - "condition": "${ .jobStatus == \"SUCCEEDED\" }", - "transition": "JobSucceeded" - }, - { - "condition": "${ .jobStatus == \"FAILED\" }", - "transition": "JobFailed" - } - ], - "defaultCondition": { - "transition": "WaitForCompletion" - } - }, - { - "name":"JobSucceeded", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "reportJobSuceeded", - "arguments": { - "name": "${ .jobuid }" - } - } - } - ], - "end": true - }, - { - "name":"JobFailed", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "reportJobFailed", - "arguments": { - "name": "${ .jobuid }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/jobmonitoring.yml b/diagram/src/test/resources/examples/jobmonitoring.yml deleted file mode 100644 index eab235d5..00000000 --- a/diagram/src/test/resources/examples/jobmonitoring.yml +++ /dev/null @@ -1,81 +0,0 @@ -id: jobmonitoring -version: '1.0' -specVersion: '0.8' -name: Job Monitoring -description: Monitor finished execution of a submitted job -start: SubmitJob -functions: - - name: submitJob - operation: http://myapis.org/monitorapi.json#doSubmit - - name: checkJobStatus - operation: http://myapis.org/monitorapi.json#checkStatus - - name: reportJobSuceeded - operation: http://myapis.org/monitorapi.json#reportSucceeded - - name: reportJobFailed - operation: http://myapis.org/monitorapi.json#reportFailure -states: - - name: SubmitJob - type: operation - actionMode: sequential - actions: - - functionRef: - refName: submitJob - arguments: - name: "${ .job.name }" - actionDataFilter: - results: "${ .jobuid }" - onErrors: - - errorRef: "AllErrors" - transition: SubmitError - stateDataFilter: - output: "${ .jobuid }" - transition: WaitForCompletion - - name: SubmitError - type: operation - actions: - - subFlowRef: handleJobSubmissionErrorWorkflow - end: true - - name: WaitForCompletion - type: sleep - duration: PT5S - transition: GetJobStatus - - name: GetJobStatus - type: operation - actionMode: sequential - actions: - - functionRef: - refName: checkJobStatus - arguments: - name: "${ .jobuid }" - actionDataFilter: - results: "${ .jobstatus }" - stateDataFilter: - output: "${ .jobstatus }" - transition: DetermineCompletion - - name: DetermineCompletion - type: switch - dataConditions: - - condition: ${ .jobStatus == "SUCCEEDED" } - transition: JobSucceeded - - condition: ${ .jobStatus == "FAILED" } - transition: JobFailed - defaultCondition: - transition: WaitForCompletion - - name: JobSucceeded - type: operation - actionMode: sequential - actions: - - functionRef: - refName: reportJobSuceeded - arguments: - name: "${ .jobuid }" - end: true - - name: JobFailed - type: operation - actionMode: sequential - actions: - - functionRef: - refName: reportJobFailed - arguments: - name: "${ .jobuid }" - end: true diff --git a/diagram/src/test/resources/examples/monitorpatient.json b/diagram/src/test/resources/examples/monitorpatient.json deleted file mode 100644 index 594bf18c..00000000 --- a/diagram/src/test/resources/examples/monitorpatient.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "id": "patientVitalsWorkflow", - "name": "Monitor Patient Vitals", - "version": "1.0", - "specVersion": "0.8", - "start": "MonitorVitals", - "events": [ - { - "name": "HighBodyTemperature", - "type": "org.monitor.highBodyTemp", - "source": "monitoringSource", - "correlation": [ - { - "contextAttributeName": "patientId" - } - ] - }, - { - "name": "HighBloodPressure", - "type": "org.monitor.highBloodPressure", - "source": "monitoringSource", - "correlation": [ - { - "contextAttributeName": "patientId" - } - ] - }, - { - "name": "HighRespirationRate", - "type": "org.monitor.highRespirationRate", - "source": "monitoringSource", - "correlation": [ - { - "contextAttributeName": "patientId" - } - ] - } - ], - "functions": [ - { - "name": "callPulmonologist", - "operation": "http://myapis.org/patientapis.json#callPulmonologist" - }, - { - "name": "sendTylenolOrder", - "operation": "http://myapis.org/patientapis.json#tylenolOrder" - }, - { - "name": "callNurse", - "operation": "http://myapis.org/patientapis.json#callNurse" - } - ], - "states": [ - { - "name": "MonitorVitals", - "type": "event", - "exclusive": true, - "onEvents": [{ - "eventRefs": ["HighBodyTemperature"], - "actions": [{ - "functionRef": { - "refName": "sendTylenolOrder", - "arguments": { - "patientid": "${ .patientId }" - } - } - }] - }, - { - "eventRefs": ["HighBloodPressure"], - "actions": [{ - "functionRef": { - "refName": "callNurse", - "arguments": { - "patientid": "${ .patientId }" - } - } - }] - }, - { - "eventRefs": ["HighRespirationRate"], - "actions": [{ - "functionRef": { - "refName": "callPulmonologist", - "arguments": { - "patientid": "${ .patientId }" - } - } - }] - } - ], - "end": { - "terminate": true - } - }] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/monitorpatient.yml b/diagram/src/test/resources/examples/monitorpatient.yml deleted file mode 100644 index c27fbea9..00000000 --- a/diagram/src/test/resources/examples/monitorpatient.yml +++ /dev/null @@ -1,56 +0,0 @@ -id: patientVitalsWorkflow -name: Monitor Patient Vitals -version: '1.0' -specVersion: '0.8' -start: MonitorVitals -events: - - name: HighBodyTemperature - type: org.monitor.highBodyTemp - source: monitoringSource - correlation: - - contextAttributeName: patientId - - name: HighBloodPressure - type: org.monitor.highBloodPressure - source: monitoringSource - correlation: - - contextAttributeName: patientId - - name: HighRespirationRate - type: org.monitor.highRespirationRate - source: monitoringSource - correlation: - - contextAttributeName: patientId -functions: - - name: callPulmonologist - operation: http://myapis.org/patientapis.json#callPulmonologist - - name: sendTylenolOrder - operation: http://myapis.org/patientapis.json#tylenolOrder - - name: callNurse - operation: http://myapis.org/patientapis.json#callNurse -states: - - name: MonitorVitals - type: event - exclusive: true - onEvents: - - eventRefs: - - HighBodyTemperature - actions: - - functionRef: - refName: sendTylenolOrder - arguments: - patientid: "${ .patientId }" - - eventRefs: - - HighBloodPressure - actions: - - functionRef: - refName: callNurse - arguments: - patientid: "${ .patientId }" - - eventRefs: - - HighRespirationRate - actions: - - functionRef: - refName: callPulmonologist - arguments: - patientid: "${ .patientId }" - end: - terminate: true diff --git a/diagram/src/test/resources/examples/parallel.json b/diagram/src/test/resources/examples/parallel.json deleted file mode 100644 index 1d614f50..00000000 --- a/diagram/src/test/resources/examples/parallel.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "id": "parallelexec", - "version": "1.0", - "specVersion": "0.8", - "name": "Parallel Execution Workflow", - "description": "Executes two branches in parallel", - "start": "ParallelExec", - "states":[ - { - "name": "ParallelExec", - "type": "parallel", - "completionType": "allOf", - "branches": [ - { - "name": "ShortDelayBranch" - }, - { - "name": "LongDelayBranch" - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/parallel.yml b/diagram/src/test/resources/examples/parallel.yml deleted file mode 100644 index 5a586cdf..00000000 --- a/diagram/src/test/resources/examples/parallel.yml +++ /dev/null @@ -1,14 +0,0 @@ -id: parallelexec -version: '1.0' -specVersion: '0.8' -name: Parallel Execution Workflow -description: Executes two branches in parallel -start: ParallelExec -states: - - name: ParallelExec - type: parallel - completionType: allOf - branches: - - name: ShortDelayBranch - - name: LongDelayBranch - end: true \ No newline at end of file diff --git a/diagram/src/test/resources/examples/periodicinboxcheck.json b/diagram/src/test/resources/examples/periodicinboxcheck.json deleted file mode 100644 index 6c1ecc96..00000000 --- a/diagram/src/test/resources/examples/periodicinboxcheck.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "id": "checkInbox", - "name": "Check Inbox Workflow", - "description": "Periodically Check Inbox", - "start": { - "stateName": "CheckInbox", - "schedule": { - "cron": "0 0/15 * * * ?" - } - }, - "version": "1.0", - "specVersion": "0.8", - "functions": [ - { - "name": "checkInboxFunction", - "operation": "http://myapis.org/inboxapi.json#checkNewMessages" - }, - { - "name": "sendTextFunction", - "operation": "http://myapis.org/inboxapi.json#sendText" - } - ], - "states": [ - { - "name": "CheckInbox", - "type": "operation", - "actionMode": "sequential", - "actions": [ - { - "functionRef": "checkInboxFunction" - } - ], - "transition": "SendTextForHighPriority" - }, - { - "name": "SendTextForHighPriority", - "type": "foreach", - "inputCollection": "${ .messages }", - "iterationParam": "singlemessage", - "actions": [ - { - "functionRef": { - "refName": "sendTextFunction", - "arguments": { - "message": "${ .singlemessage }" - } - } - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/periodicinboxcheck.yml b/diagram/src/test/resources/examples/periodicinboxcheck.yml deleted file mode 100644 index d04932e6..00000000 --- a/diagram/src/test/resources/examples/periodicinboxcheck.yml +++ /dev/null @@ -1,31 +0,0 @@ -id: checkInbox -name: Check Inbox Workflow -description: Periodically Check Inbox -start: - stateName: CheckInbox - schedule: - cron: 0 0/15 * * * ? -version: '1.0' -specVersion: '0.8' -functions: - - name: checkInboxFunction - operation: http://myapis.org/inboxapi.json#checkNewMessages - - name: sendTextFunction - operation: http://myapis.org/inboxapi.json#sendText -states: - - name: CheckInbox - type: operation - actionMode: sequential - actions: - - functionRef: checkInboxFunction - transition: SendTextForHighPriority - - name: SendTextForHighPriority - type: foreach - inputCollection: "${ .messages }" - iterationParam: singlemessage - actions: - - functionRef: - refName: sendTextFunction - arguments: - message: "${ .singlemessage }" - end: true \ No newline at end of file diff --git a/diagram/src/test/resources/examples/provisionorder.json b/diagram/src/test/resources/examples/provisionorder.json deleted file mode 100644 index 57d3b33a..00000000 --- a/diagram/src/test/resources/examples/provisionorder.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "id": "provisionorders", - "version": "1.0", - "specVersion": "0.8", - "name": "Provision Orders", - "description": "Provision Orders and handle errors thrown", - "start": "ProvisionOrder", - "functions": [ - { - "name": "provisionOrderFunction", - "operation": "http://myapis.org/provisioningapi.json#doProvision" - } - ], - "states":[ - { - "name":"ProvisionOrder", - "type":"operation", - "actionMode":"sequential", - "actions":[ - { - "functionRef": { - "refName": "provisionOrderFunction", - "arguments": { - "order": "${ .order }" - } - } - } - ], - "stateDataFilter": { - "output": "${ .exceptions }" - }, - "transition": "ApplyOrder", - "onErrors": [ - { - "errorRef": "Missing order id", - "transition": "MissingId" - }, - { - "errorRef": "Missing order item", - "transition": "MissingItem" - }, - { - "errorRef": "Missing order quantity", - "transition": "MissingQuantity" - } - ] - }, - { - "name": "MissingId", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleMissingIdExceptionWorkflow" - } - ], - "end": true - }, - { - "name": "MissingItem", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleMissingItemExceptionWorkflow" - } - ], - "end": true - }, - { - "name": "MissingQuantity", - "type": "operation", - "actions": [ - { - "subFlowRef": "handleMissingQuantityExceptionWorkflow" - } - ], - "end": true - }, - { - "name": "ApplyOrder", - "type": "operation", - "actions": [ - { - "subFlowRef": "applyOrderWorkflowId" - } - ], - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/provisionorder.yml b/diagram/src/test/resources/examples/provisionorder.yml deleted file mode 100644 index 7233e5c3..00000000 --- a/diagram/src/test/resources/examples/provisionorder.yml +++ /dev/null @@ -1,48 +0,0 @@ -id: provisionorders -version: '1.0' -specVersion: '0.8' -name: Provision Orders -description: Provision Orders and handle errors thrown -start: ProvisionOrder -functions: - - name: provisionOrderFunction - operation: http://myapis.org/provisioningapi.json#doProvision -states: - - name: ProvisionOrder - type: operation - actionMode: sequential - actions: - - functionRef: - refName: provisionOrderFunction - arguments: - order: "${ .order }" - stateDataFilter: - output: "${ .exceptions }" - transition: ApplyOrder - onErrors: - - errorRef: Missing order id - transition: MissingId - - errorRef: Missing order item - transition: MissingItem - - errorRef: Missing order quantity - transition: MissingQuantity - - name: MissingId - type: operation - actions: - - subFlowRef: handleMissingIdExceptionWorkflow - end: true - - name: MissingItem - type: operation - actions: - - subFlowRef: handleMissingItemExceptionWorkflow - end: true - - name: MissingQuantity - type: operation - actions: - - subFlowRef: handleMissingQuantityExceptionWorkflow - end: true - - name: ApplyOrder - type: operation - actions: - - subFlowRef: applyOrderWorkflowId - end: true diff --git a/diagram/src/test/resources/examples/roomreadings.json b/diagram/src/test/resources/examples/roomreadings.json deleted file mode 100644 index 14f58b9b..00000000 --- a/diagram/src/test/resources/examples/roomreadings.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "id": "roomreadings", - "name": "Room Temp and Humidity Workflow", - "version": "1.0", - "specVersion": "0.8", - "start": "ConsumeReading", - "timeouts": { - "workflowExecTimeout": { - "duration": "PT1H", - "runBefore": "GenerateReport" - } - }, - "keepActive": true, - "states": [ - { - "name": "ConsumeReading", - "type": "event", - "onEvents": [ - { - "eventRefs": ["TemperatureEvent", "HumidityEvent"], - "actions": [ - { - "functionRef": { - "refName": "LogReading" - } - } - ], - "eventDataFilter": { - "data": "${ .readings }" - } - } - ], - "end": true - }, - { - "name": "GenerateReport", - "type": "operation", - "actions": [ - { - "functionRef": { - "refName": "ProduceReport", - "arguments": { - "data": "${ .readings }" - } - } - } - ], - "end": { - "terminate": true - } - } - ], - "events": [ - { - "name": "TemperatureEvent", - "type": "my.home.sensors", - "source": "/home/rooms/+", - "correlation": [ - { - "contextAttributeName": "roomId" - } - ] - }, - { - "name": "HumidityEvent", - "type": "my.home.sensors", - "source": "/home/rooms/+", - "correlation": [ - { - "contextAttributeName": "roomId" - } - ] - } - ], - "functions": [ - { - "name": "LogReading", - "operation": "http.myorg.io/ordersservices.json#logreading" - }, - { - "name": "ProduceReport", - "operation": "http.myorg.io/ordersservices.json#produceReport" - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/roomreadings.yml b/diagram/src/test/resources/examples/roomreadings.yml deleted file mode 100644 index 948de4a0..00000000 --- a/diagram/src/test/resources/examples/roomreadings.yml +++ /dev/null @@ -1,48 +0,0 @@ -id: roomreadings -name: Room Temp and Humidity Workflow -version: '1.0' -specVersion: '0.8' -start: ConsumeReading -timeouts: - workflowExecTimeout: - duration: PT1H - runBefore: GenerateReport -keepActive: true -states: - - name: ConsumeReading - type: event - onEvents: - - eventRefs: - - TemperatureEvent - - HumidityEvent - actions: - - functionRef: - refName: LogReading - eventDataFilter: - data: "${ .readings }" - end: true - - name: GenerateReport - type: operation - actions: - - functionRef: - refName: ProduceReport - arguments: - data: "${ .readings }" - end: - terminate: true -events: - - name: TemperatureEvent - type: my.home.sensors - source: "/home/rooms/+" - correlation: - - contextAttributeName: roomId - - name: HumidityEvent - type: my.home.sensors - source: "/home/rooms/+" - correlation: - - contextAttributeName: roomId -functions: - - name: LogReading - operation: http.myorg.io/ordersservices.json#logreading - - name: ProduceReport - operation: http.myorg.io/ordersservices.json#produceReport diff --git a/diagram/src/test/resources/examples/sendcloudevent.json b/diagram/src/test/resources/examples/sendcloudevent.json deleted file mode 100644 index 14cd9cad..00000000 --- a/diagram/src/test/resources/examples/sendcloudevent.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "id": "sendcloudeventonprovision", - "version": "1.0", - "specVersion": "0.8", - "name": "Send CloudEvent on provision completion", - "start": "ProvisionOrdersState", - "events": [ - { - "name": "provisioningCompleteEvent", - "type": "provisionCompleteType", - "kind": "produced" - } - ], - "functions": [ - { - "name": "provisionOrderFunction", - "operation": "http://myapis.org/provisioning.json#doProvision" - } - ], - "states": [ - { - "name": "ProvisionOrdersState", - "type": "foreach", - "inputCollection": "${ .orders }", - "iterationParam": "singleorder", - "outputCollection": "${ .provisionedOrders }", - "actions": [ - { - "functionRef": { - "refName": "provisionOrderFunction", - "arguments": { - "order": "${ .singleorder }" - } - } - } - ], - "end": { - "produceEvents": [{ - "eventRef": "provisioningCompleteEvent", - "data": "${ .provisionedOrders }" - }] - } - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/sendcloudevent.yml b/diagram/src/test/resources/examples/sendcloudevent.yml deleted file mode 100644 index 037b0648..00000000 --- a/diagram/src/test/resources/examples/sendcloudevent.yml +++ /dev/null @@ -1,27 +0,0 @@ -id: sendcloudeventonprovision -version: '1.0' -specVersion: '0.8' -name: Send CloudEvent on provision completion -start: ProvisionOrdersState -events: - - name: provisioningCompleteEvent - type: provisionCompleteType - kind: produced -functions: - - name: provisionOrderFunction - operation: http://myapis.org/provisioning.json#doProvision -states: - - name: ProvisionOrdersState - type: foreach - inputCollection: "${ .orders }" - iterationParam: singleorder - outputCollection: "${ .provisionedOrders }" - actions: - - functionRef: - refName: provisionOrderFunction - arguments: - order: "${ .singleorder }" - end: - produceEvents: - - eventRef: provisioningCompleteEvent - data: "${ .provisionedOrders }" \ No newline at end of file diff --git a/diagram/src/test/resources/examples/singleeventstate.json b/diagram/src/test/resources/examples/singleeventstate.json deleted file mode 100644 index 7e8607a0..00000000 --- a/diagram/src/test/resources/examples/singleeventstate.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "id": "testEvents", - "name": "Test Events Workflow", - "description": "This is a test events workflow", - "version": "1.0", - "specVersion": "0.8", - "start": "EventState", - "events": [ - { - "name": "event1", - "source": "event1source", - "type": "event1type" - }, - { - "name": "event2", - "source": "evet2source", - "type": "event2type" - }, - { - "name": "event3", - "source": "event3source", - "type": "event3type" - }, - { - "name": "event4", - "source": "event4source", - "type": "event4type" - } - ], - "states": [ - { - "name": "EventState", - "type": "event", - "end": true, - "onEvents": [ - { - "eventRefs": ["event1", "event2"], - "actions": [] - }, - { - "eventRefs": ["event3", "event4"], - "actions": [] - } - ] - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/singleeventstate.yml b/diagram/src/test/resources/examples/singleeventstate.yml deleted file mode 100644 index 776625fc..00000000 --- a/diagram/src/test/resources/examples/singleeventstate.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: testEvents -name: Test Events Workflow -description: This is a test events workflow -version: '1.0' -specVersion: '0.8' -start: EventState -events: - - name: event1 - source: event1source - type: event1type - - name: event2 - source: evet2source - type: event2type - - name: event3 - source: event3source - type: event3type - - name: event4 - source: event4source - type: event4type -states: - - name: EventState - type: event - end: true - onEvents: - - eventRefs: - - event1 - - event2 - actions: [] - - eventRefs: - - event3 - - event4 - actions: [] diff --git a/diagram/src/test/resources/examples/singleswitchstate.json b/diagram/src/test/resources/examples/singleswitchstate.json deleted file mode 100644 index ee7a7ba4..00000000 --- a/diagram/src/test/resources/examples/singleswitchstate.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "id": "testSwitch", - "name": "Test Switch State Workflow", - "description": "This is a test switch state workflow", - "version": "1.0", - "specVersion": "0.8", - "start": "SwitchIt", - "states": [ - { - "name": "SwitchIt", - "type": "switch", - "dataConditions": [ - { - "name": "first", - "condition": "", - "transition": "FromFirstCondition" - }, - { - "name": "second", - "condition": "", - "transition": "FromSecondCondition" - }, - { - "name": "third", - "condition": "", - "end": true - }, - { - "name": "fourth", - "condition": "", - "end": true - } - ] - }, - { - "name": "FromFirstCondition", - "type": "sleep", - "duration": "PT2M", - "end": true - }, - { - "name": "FromSecondCondition", - "type": "inject", - "data": {}, - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/singleswitchstate.yml b/diagram/src/test/resources/examples/singleswitchstate.yml deleted file mode 100644 index eeb32233..00000000 --- a/diagram/src/test/resources/examples/singleswitchstate.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- -id: testSwitch -name: Test Switch State Workflow -description: This is a test switch state workflow -version: '1.0' -specVersion: '0.8' -start: SwitchIt -states: - - name: SwitchIt - type: switch - dataConditions: - - name: first - condition: '' - transition: FromFirstCondition - - name: second - condition: '' - transition: FromSecondCondition - - name: third - condition: '' - end: true - - name: fourth - condition: '' - end: true - - name: FromFirstCondition - type: sleep - duration: PT2M - end: true - - name: FromSecondCondition - type: inject - data: {} - end: true diff --git a/diagram/src/test/resources/examples/singleswitchstateeventconditions.json b/diagram/src/test/resources/examples/singleswitchstateeventconditions.json deleted file mode 100644 index e3478696..00000000 --- a/diagram/src/test/resources/examples/singleswitchstateeventconditions.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "id": "testSwitch", - "name": "Test Switch State Workflow", - "description": "This is a test switch state workflow", - "version": "1.0", - "specVersion": "0.8", - "start": "SwitchIt", - "states": [ - { - "name": "SwitchIt", - "type": "switch", - "eventConditions": [ - { - "name": "first", - "eventRef": "firstEvent", - "transition": "FromFirstCondition" - }, - { - "name": "second", - "eventRef": "secondEvent", - "transition": "FromSecondCondition" - }, - { - "name": "third", - "eventRef": "thirdEvent", - "end": true - }, - { - "name": "fourth", - "eventRef": "fourthEvent", - "end": true - } - ] - }, - { - "name": "FromFirstCondition", - "type": "sleep", - "duration": "PT2M", - "end": true - }, - { - "name": "FromSecondCondition", - "type": "inject", - "data": {}, - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/singleswitchstateeventconditions.yml b/diagram/src/test/resources/examples/singleswitchstateeventconditions.yml deleted file mode 100644 index 1fe4a29b..00000000 --- a/diagram/src/test/resources/examples/singleswitchstateeventconditions.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- -id: testSwitch -name: Test Switch State Workflow -description: This is a test switch state workflow -version: '1.0' -specVersion: '0.8' -start: SwitchIt -states: - - name: SwitchIt - type: switch - eventConditions: - - name: first - eventRef: firstEvent - transition: FromFirstCondition - - name: second - eventRef: secondEvent - transition: FromSecondCondition - - name: third - eventRef: thirdEvent - end: true - - name: fourth - eventRef: fourthEvent - end: true - - name: FromFirstCondition - type: sleep - duration: PT2M - end: true - - name: FromSecondCondition - type: inject - data: {} - end: true diff --git a/diagram/src/test/resources/examples/solvemathproblems.json b/diagram/src/test/resources/examples/solvemathproblems.json deleted file mode 100644 index 29c9de38..00000000 --- a/diagram/src/test/resources/examples/solvemathproblems.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "id": "solvemathproblems", - "version": "1.0", - "specVersion": "0.8", - "name": "Solve Math Problems Workflow", - "description": "Solve math problems", - "start": "Solve", - "functions": [ - { - "name": "solveMathExpressionFunction", - "operation": "http://myapis.org/mapthapis.json#solveExpression" - } - ], - "states":[ - { - "name":"Solve", - "type":"foreach", - "inputCollection": "${ .expressions }", - "iterationParam": "singleexpression", - "outputCollection": "${ .results }", - "actions":[ - { - "functionRef": { - "refName": "solveMathExpressionFunction", - "arguments": { - "expression": "${ .singleexpression }" - } - } - } - ], - "stateDataFilter": { - "output": "${ .results }" - }, - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/solvemathproblems.yml b/diagram/src/test/resources/examples/solvemathproblems.yml deleted file mode 100644 index 883c3e1b..00000000 --- a/diagram/src/test/resources/examples/solvemathproblems.yml +++ /dev/null @@ -1,23 +0,0 @@ -id: solvemathproblems -version: '1.0' -specVersion: '0.8' -name: Solve Math Problems Workflow -description: Solve math problems -start: Solve -functions: - - name: solveMathExpressionFunction - operation: http://myapis.org/mapthapis.json#solveExpression -states: - - name: Solve - type: foreach - inputCollection: "${ .expressions }" - iterationParam: singleexpression - outputCollection: "${ .results }" - actions: - - functionRef: - refName: solveMathExpressionFunction - arguments: - expression: "${ .singleexpression }" - stateDataFilter: - output: "${ .results }" - end: true \ No newline at end of file diff --git a/diagram/src/test/resources/examples/vetappointmentservice.json b/diagram/src/test/resources/examples/vetappointmentservice.json deleted file mode 100644 index 92db914e..00000000 --- a/diagram/src/test/resources/examples/vetappointmentservice.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "id": "VetAppointmentWorkflow", - "name": "Vet Appointment Workflow", - "description": "Vet service call via events", - "version": "1.0", - "specVersion": "0.8", - "start": "MakeVetAppointmentState", - "events": [ - { - "name": "MakeVetAppointment", - "source": "VetServiceSoure", - "kind": "produced" - }, - { - "name": "VetAppointmentInfo", - "source": "VetServiceSource", - "kind": "consumed" - } - ], - "states": [ - { - "name": "MakeVetAppointmentState", - "type": "operation", - "actions": [ - { - "name": "MakeAppointmentAction", - "eventRef": { - "triggerEventRef": "MakeVetAppointment", - "data": "${ .patientInfo }", - "resultEventRef": "VetAppointmentInfo" - }, - "actionDataFilter": { - "results": "${ .appointmentInfo }" - } - } - ], - "timeouts": { - "actionExecTimeout": "PT15M" - }, - "end": true - } - ] -} \ No newline at end of file diff --git a/diagram/src/test/resources/examples/vetappointmentservice.yml b/diagram/src/test/resources/examples/vetappointmentservice.yml deleted file mode 100644 index d102f32b..00000000 --- a/diagram/src/test/resources/examples/vetappointmentservice.yml +++ /dev/null @@ -1,27 +0,0 @@ -id: VetAppointmentWorkflow -name: Vet Appointment Workflow -description: Vet service call via events -version: '1.0' -specVersion: '0.8' -start: MakeVetAppointmentState -events: - - name: MakeVetAppointment - source: VetServiceSoure - kind: produced - - name: VetAppointmentInfo - source: VetServiceSource - kind: consumed -states: - - name: MakeVetAppointmentState - type: operation - actions: - - name: MakeAppointmentAction - eventRef: - triggerEventRef: MakeVetAppointment - data: "${ .patientInfo }" - resultEventRef: VetAppointmentInfo - actionDataFilter: - results: "${ .appointmentInfo }" - timeouts: - actionExecTimeout: PT15M - end: true diff --git a/diagram/src/test/resources/templates/plantuml/custom-template.txt b/diagram/src/test/resources/templates/plantuml/custom-template.txt deleted file mode 100644 index e162afc5..00000000 --- a/diagram/src/test/resources/templates/plantuml/custom-template.txt +++ /dev/null @@ -1,46 +0,0 @@ -@startuml -skinparam backgroundColor White -skinparam legendBackgroundColor White -skinparam legendBorderColor White -skinparam state { - StartColor Green - EndColor Orange - BackgroundColor GhostWhite - BackgroundColor<< workflow >> White - BorderColor Black - ArrowColor Black - - BorderColor<< event >> #7fe5f0 - BorderColor<< operation >> #bada55 - BorderColor<< switch >> #92a0f2 - BorderColor<< sleep >> #b83b5e - BorderColor<< parallel >> #6a2c70 - BorderColor<< inject >> #1e5f74 - BorderColor<< foreach >> #931a25 - BorderColor<< callback >> #ffcb8e -} -state "[(${diagram.title})]" as workflow << workflow >> { - -[# th:each="stateDef : ${diagram.modelStateDefs}" ] -[(${stateDef.toString()})] -[/] - -[# th:each="state : ${diagram.modelStates}" ] -[(${state.toString()})] -[/] - -[# th:each="connection : ${diagram.modelConnections}" ] -[(${connection.toString()})] -[/] - -} - -[# th:if="${diagram.showLegend}" ] -legend center -State Types and Border Colors: -| Event | Operation | Switch | Sleep | Parallel | Inject | ForEach | CallBack | -|<#7fe5f0>|<#bada55>|<#92a0f2>|<#b83b5e>|<#6a2c70>|<#1e5f74>|<#931a25>|| -endlegend -[/] - -@enduml \ No newline at end of file diff --git a/img/jobmonitoring.png b/img/jobmonitoring.png deleted file mode 100644 index cf53109a208f0a981e0cd430819a0bd451770a6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120051 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≪k9R6p*Lk)R1cjM9CK9OE#s+cg(qVxhu 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 Cly40H diff --git a/img/provisionorders.png b/img/provisionorders.png deleted file mode 100644 index e8fc69f53ecd62b785a54a012c024d9a4aa5491f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51023 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 diff --git a/pom.xml b/pom.xml index a0e56216..3cb9c69d 100644 --- a/pom.xml +++ b/pom.xml @@ -50,22 +50,17 @@ 3.2.0 - 3.4.0 + 3.3.1 3.13.0 3.1.2 - 3.5.0 + 3.0.0-M2 3.2.5 2.23 3.2.4 3.4.1 ${java.version} -<<<<<<< Upstream, based on main - 1.1.2 - 3.7.0 -======= 1.2.1 - 3.6.3 ->>>>>>> 008f450 [Fix_#359] Migration to 0.10 DSL + 3.7.0 3.0.1 3.3.1 3.2.5 diff --git a/spi/.gitignore b/spi/.gitignore deleted file mode 100644 index d4dfde66..00000000 --- a/spi/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/** -!**/src/test/** - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ - -### VS Code ### -.vscode/ \ No newline at end of file diff --git a/spi/pom.xml b/spi/pom.xml deleted file mode 100644 index b04be92b..00000000 --- a/spi/pom.xml +++ /dev/null @@ -1,124 +0,0 @@ - - 4.0.0 - - - io.serverlessworkflow - serverlessworkflow-parent - 7.0.0-SNAPSHOT - - - serverlessworkflow-spi - Serverless Workflow :: SPI - jar - Java SDK for Serverless Workflow Specification - - - - org.slf4j - slf4j-api - - - - io.serverlessworkflow - serverlessworkflow-api - ${project.version} - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.jupiter - junit-jupiter-params - test - - - org.mockito - mockito-core - test - - - ch.qos.logback - logback-classic - test - - - org.assertj - assertj-core - test - - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - - - - - - - - - - - - ${project.build.directory}/checkstyle.log - true - true - true - false - false - ${checkstyle.logViolationsToConsole} - ${checkstyle.failOnViolation} - - ${project.build.sourceDirectory} - ${project.build.testSourceDirectory} - - - - - compile - - check - - - - - - com.spotify.fmt - fmt-maven-plugin - - src/main/java - src/test/java - false - .*\.java - false - false - - - - - - format - - - - - - - \ No newline at end of file diff --git a/spi/src/main/java/io/serverlessworkflow/spi/WorkflowDiagramProvider.java b/spi/src/main/java/io/serverlessworkflow/spi/WorkflowDiagramProvider.java deleted file mode 100644 index ad0e8180..00000000 --- a/spi/src/main/java/io/serverlessworkflow/spi/WorkflowDiagramProvider.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.spi; - -import io.serverlessworkflow.api.interfaces.WorkflowDiagram; -import java.util.Iterator; -import java.util.ServiceLoader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class WorkflowDiagramProvider { - private WorkflowDiagram workflowDiagram; - - private static Logger logger = LoggerFactory.getLogger(WorkflowDiagramProvider.class); - - public WorkflowDiagramProvider() { - ServiceLoader foundWorkflowDiagrams = - ServiceLoader.load(WorkflowDiagram.class); - Iterator it = foundWorkflowDiagrams.iterator(); - if (it.hasNext()) { - workflowDiagram = it.next(); - logger.info("Found workflow diagram: " + workflowDiagram.toString()); - } - } - - private static class LazyHolder { - - static final WorkflowDiagramProvider INSTANCE = new WorkflowDiagramProvider(); - } - - public static WorkflowDiagramProvider getInstance() { - return WorkflowDiagramProvider.LazyHolder.INSTANCE; - } - - public WorkflowDiagram get() { - return workflowDiagram; - } -} diff --git a/spi/src/main/java/io/serverlessworkflow/spi/WorkflowPropertySourceProvider.java b/spi/src/main/java/io/serverlessworkflow/spi/WorkflowPropertySourceProvider.java deleted file mode 100644 index ef3bcf40..00000000 --- a/spi/src/main/java/io/serverlessworkflow/spi/WorkflowPropertySourceProvider.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.spi; - -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.util.Iterator; -import java.util.ServiceLoader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class WorkflowPropertySourceProvider { - private WorkflowPropertySource workflowPropertySource; - - private static Logger logger = LoggerFactory.getLogger(WorkflowValidatorProvider.class); - - public WorkflowPropertySourceProvider() { - ServiceLoader foundPropertyContext = - ServiceLoader.load(WorkflowPropertySource.class); - Iterator it = foundPropertyContext.iterator(); - if (it.hasNext()) { - workflowPropertySource = it.next(); - logger.info("Found property source: " + workflowPropertySource.toString()); - } - } - - private static class LazyHolder { - - static final WorkflowPropertySourceProvider INSTANCE = new WorkflowPropertySourceProvider(); - } - - public static WorkflowPropertySourceProvider getInstance() { - return WorkflowPropertySourceProvider.LazyHolder.INSTANCE; - } - - public WorkflowPropertySource get() { - return workflowPropertySource; - } -} diff --git a/spi/src/main/java/io/serverlessworkflow/spi/WorkflowValidatorProvider.java b/spi/src/main/java/io/serverlessworkflow/spi/WorkflowValidatorProvider.java deleted file mode 100644 index 815f5fb6..00000000 --- a/spi/src/main/java/io/serverlessworkflow/spi/WorkflowValidatorProvider.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.spi; - -import io.serverlessworkflow.api.interfaces.WorkflowValidator; -import java.util.Iterator; -import java.util.ServiceLoader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class WorkflowValidatorProvider { - private WorkflowValidator workflowValidator; - - private static Logger logger = LoggerFactory.getLogger(WorkflowValidatorProvider.class); - - public WorkflowValidatorProvider() { - ServiceLoader foundWorkflowValidators = - ServiceLoader.load(WorkflowValidator.class); - Iterator it = foundWorkflowValidators.iterator(); - if (it.hasNext()) { - workflowValidator = it.next(); - logger.info("Found workflow validator: " + workflowValidator.toString()); - } - } - - private static class LazyHolder { - - static final WorkflowValidatorProvider INSTANCE = new WorkflowValidatorProvider(); - } - - public static WorkflowValidatorProvider getInstance() { - return LazyHolder.INSTANCE; - } - - public WorkflowValidator get() { - return workflowValidator; - } -} diff --git a/spi/src/test/java/io/serverlessworkflow/spi/test/ServiceProvidersTest.java b/spi/src/test/java/io/serverlessworkflow/spi/test/ServiceProvidersTest.java deleted file mode 100644 index b6ec9c73..00000000 --- a/spi/src/test/java/io/serverlessworkflow/spi/test/ServiceProvidersTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.spi.test; - -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import io.serverlessworkflow.api.interfaces.WorkflowValidator; -import io.serverlessworkflow.spi.WorkflowPropertySourceProvider; -import io.serverlessworkflow.spi.WorkflowValidatorProvider; -import io.serverlessworkflow.spi.test.providers.TestWorkflowPropertySource; -import io.serverlessworkflow.spi.test.providers.TestWorkflowValidator; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class ServiceProvidersTest { - - @Test - public void testWorkflowValidatorProvider() { - WorkflowValidator validator = WorkflowValidatorProvider.getInstance().get(); - Assertions.assertNotNull(validator); - Assertions.assertTrue(validator instanceof TestWorkflowValidator); - } - - @Test - public void testWorkflowPropertySourceProvider() { - WorkflowPropertySource propertySource = WorkflowPropertySourceProvider.getInstance().get(); - Assertions.assertNotNull(propertySource); - Assertions.assertTrue(propertySource instanceof TestWorkflowPropertySource); - } -} diff --git a/spi/src/test/java/io/serverlessworkflow/spi/test/providers/TestWorkflowPropertySource.java b/spi/src/test/java/io/serverlessworkflow/spi/test/providers/TestWorkflowPropertySource.java deleted file mode 100644 index a17bbdde..00000000 --- a/spi/src/test/java/io/serverlessworkflow/spi/test/providers/TestWorkflowPropertySource.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.spi.test.providers; - -import io.serverlessworkflow.api.interfaces.WorkflowPropertySource; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -public class TestWorkflowPropertySource implements WorkflowPropertySource { - - private Properties source = new Properties(); - - @Override - public Properties getPropertySource() { - Map propertySourcetMap = new HashMap<>(); - propertySourcetMap.put("wfname", "test-wf"); - propertySourcetMap.put("delaystate.name", "delay-state"); - propertySourcetMap.put("delaystate.timedelay", "PT5S"); - propertySourcetMap.put("delaystate.type", "DELAY"); - - source.putAll(propertySourcetMap); - - return source; - } - - @Override - public void setPropertySource(Properties source) { - this.source = source; - } -} diff --git a/spi/src/test/java/io/serverlessworkflow/spi/test/providers/TestWorkflowValidator.java b/spi/src/test/java/io/serverlessworkflow/spi/test/providers/TestWorkflowValidator.java deleted file mode 100644 index 14d38137..00000000 --- a/spi/src/test/java/io/serverlessworkflow/spi/test/providers/TestWorkflowValidator.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.spi.test.providers; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.WorkflowValidator; -import io.serverlessworkflow.api.validation.ValidationError; -import java.util.List; - -public class TestWorkflowValidator implements WorkflowValidator { - - @Override - public WorkflowValidator setWorkflow(Workflow workflow) { - return this; - } - - @Override - public WorkflowValidator setSource(String source) { - return this; - } - - @Override - public List validate() { - return null; - } - - @Override - public boolean isValid() { - return false; - } - - @Override - public WorkflowValidator setSchemaValidationEnabled(boolean schemaValidationEnabled) { - return this; - } - - @Override - public WorkflowValidator reset() { - return this; - } -} diff --git a/spi/src/test/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowPropertySource b/spi/src/test/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowPropertySource deleted file mode 100644 index ce3c644b..00000000 --- a/spi/src/test/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowPropertySource +++ /dev/null @@ -1 +0,0 @@ -io.serverlessworkflow.spi.test.providers.TestWorkflowPropertySource \ No newline at end of file diff --git a/spi/src/test/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowValidator b/spi/src/test/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowValidator deleted file mode 100644 index d25b29d9..00000000 --- a/spi/src/test/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowValidator +++ /dev/null @@ -1 +0,0 @@ -io.serverlessworkflow.spi.test.providers.TestWorkflowValidator \ No newline at end of file diff --git a/utils/pom.xml b/utils/pom.xml deleted file mode 100644 index 62d90e8d..00000000 --- a/utils/pom.xml +++ /dev/null @@ -1,124 +0,0 @@ - - 4.0.0 - - - io.serverlessworkflow - serverlessworkflow-parent - 7.0.0-SNAPSHOT - - - serverlessworkflow-util - Serverless Workflow :: Utils - jar - Java SDK for Serverless Workflow Specification - - - - org.slf4j - slf4j-api - - - - io.serverlessworkflow - serverlessworkflow-api - ${project.version} - - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.jupiter - junit-jupiter-params - test - - - org.mockito - mockito-core - test - - - ch.qos.logback - logback-classic - test - - - org.assertj - assertj-core - test - - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - - - - - - - - - - - - ${project.build.directory}/checkstyle.log - true - true - true - false - false - ${checkstyle.logViolationsToConsole} - ${checkstyle.failOnViolation} - - ${project.build.sourceDirectory} - ${project.build.testSourceDirectory} - - - - - compile - - check - - - - - - com.spotify.fmt - fmt-maven-plugin - - src/main/java - src/test/java - false - .*\.java - false - false - - - - - - format - - - - - - - \ No newline at end of file diff --git a/utils/src/main/java/io/serverlessworkflow/utils/WorkflowUtils.java b/utils/src/main/java/io/serverlessworkflow/utils/WorkflowUtils.java deleted file mode 100644 index 671d3c50..00000000 --- a/utils/src/main/java/io/serverlessworkflow/utils/WorkflowUtils.java +++ /dev/null @@ -1,665 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.utils; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.actions.Action; -import io.serverlessworkflow.api.branches.Branch; -import io.serverlessworkflow.api.defaultdef.DefaultConditionDefinition; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.api.events.OnEvents; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.functions.FunctionRef; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.start.Start; -import io.serverlessworkflow.api.states.*; -import io.serverlessworkflow.api.switchconditions.DataCondition; -import io.serverlessworkflow.api.switchconditions.EventCondition; -import java.util.*; -import java.util.stream.Collectors; - -/** Provides common utility methods to provide most often needed answers from a workflow */ -@SuppressWarnings("StreamToLoop") -public final class WorkflowUtils { - private static final int DEFAULT_STARTING_STATE_POSITION = 0; - private static final long DEFAULT_STATE_COUNT = 0; - - /** - * Gets State matching Start state. If start is not present returns first state. If start is - * present, returns the matching start State. If matching state is not present, returns null - * - * @param workflow workflow - * @return {@code state} when present else returns {@code null} - */ - public static State getStartingState(Workflow workflow) { - if (!hasStates(workflow)) { - return null; - } - - Start start = workflow.getStart(); - if (start == null) { - return workflow.getStates().get(DEFAULT_STARTING_STATE_POSITION); - } else { - Optional startingState = - workflow.getStates().stream() - .filter(state -> state.getName().equals(start.getStateName())) - .findFirst(); - return startingState.orElse(null); - } - } - - /** - * Gets List of States matching stateType - * - * @param workflow - * @param stateType - * @return {@code List}. Returns {@code null} when workflow is null. - */ - public static List getStates(Workflow workflow, DefaultState.Type stateType) { - if (!hasStates(workflow)) { - return null; - } - - return workflow.getStates().stream() - .filter(state -> state.getType() == stateType) - .collect(Collectors.toList()); - } - - /** - * @return {@code List}. Returns {@code NULL} - * when workflow is null or when workflow does not contain events - */ - public static List getDefinedConsumedEvents(Workflow workflow) { - return getDefinedEvents(workflow, EventDefinition.Kind.CONSUMED); - } - - /** - * @return {@code List}. Returns {@code NULL} - * when workflow is null or when workflow does not contain events - */ - public static List getDefinedProducedEvents(Workflow workflow) { - return getDefinedEvents(workflow, EventDefinition.Kind.PRODUCED); - } - - /** - * Gets list of event definition matching eventKind - * - * @param workflow - * @return {@code List}. Returns {@code NULL} - * when workflow is null or when workflow does not contain events - */ - public static List getDefinedEvents( - Workflow workflow, EventDefinition.Kind eventKind) { - if (!hasEventDefs(workflow)) { - return null; - } - - List eventDefs = workflow.getEvents().getEventDefs(); - return eventDefs.stream() - .filter(eventDef -> eventDef.getKind() == eventKind) - .collect(Collectors.toList()); - } - - /** - * @return {@code int} Returns count of defined event count matching eventKind - */ - public static int getDefinedEventsCount(Workflow workflow, EventDefinition.Kind eventKind) { - List definedEvents = getDefinedEvents(workflow, eventKind); - return definedEvents == null ? 0 : definedEvents.size(); - } - - /** - * @return {@code int} Returns count of Defined Consumed Event Count - */ - public static int getDefinedConsumedEventsCount(Workflow workflow) { - return getDefinedEventsCount(workflow, EventDefinition.Kind.CONSUMED); - } - - /** - * @return {@code int} Returns count of Defined Produced Event Count - */ - public static int getDefinedProducedEventsCount(Workflow workflow) { - return getDefinedEventsCount(workflow, EventDefinition.Kind.PRODUCED); - } - - /** - * Gets Consumed Events of parent workflow Iterates through states in parent workflow and collects - * all the ConsumedEvents. Sub Workflows of the Workflow are not considered for - * getting Consumed Events - * - * @return Returns {@code List} - */ - public static List getWorkflowConsumedEvents(Workflow workflow) { - return getWorkflowEventDefinitions(workflow, EventDefinition.Kind.CONSUMED); - } - - /** - * Gets Produced Events of parent workflow Iterates through states in parent workflow and collects - * all the ConsumedEvents. Sub Workflows of the Workflow are not considered for - * getting Consumed Events - * - * @return Returns {@code List} - */ - public static List getWorkflowProducedEvents(Workflow workflow) { - return getWorkflowEventDefinitions(workflow, EventDefinition.Kind.PRODUCED); - } - - /** - * Gets Events of parent workflow matching {@code EventDefinition.Kind} Iterates through states in - * parent workflow and collects all the events matching {@code EventDefinition.Kind} . - * - * @return Returns {@code List} - */ - public static List getWorkflowEventDefinitions( - Workflow workflow, EventDefinition.Kind eventKind) { - if (!hasStates(workflow)) { - return null; - } - - List uniqueWorkflowEventsFromStates = getUniqueWorkflowEventsFromStates(workflow); - List definedConsumedEvents = getDefinedEvents(workflow, eventKind); - if (definedConsumedEvents == null) { - return null; - } - return definedConsumedEvents.stream() - .filter(definedEvent -> uniqueWorkflowEventsFromStates.contains(definedEvent.getName())) - .collect(Collectors.toList()); - } - - /** Returns a list of unique event names from workflow states */ - public static List getUniqueWorkflowEventsFromStates(Workflow workflow) { - List eventReferences = new ArrayList<>(); - - for (State state : workflow.getStates()) { - if (state instanceof SwitchState) { - SwitchState switchState = (SwitchState) state; - if (switchState.getEventConditions() != null) { - switchState - .getEventConditions() - .forEach(eventCondition -> eventReferences.add(eventCondition.getEventRef())); - } - } else if (state instanceof CallbackState) { - CallbackState callbackState = (CallbackState) state; - if (callbackState.getEventRef() != null) eventReferences.add(callbackState.getEventRef()); - if (callbackState.getAction() != null && callbackState.getAction().getEventRef() != null) { - eventReferences.addAll(getActionEvents(callbackState.getAction())); - } - } else if (state instanceof EventState) { - EventState eventState = (EventState) state; - if (eventState.getOnEvents() != null) { - eventState - .getOnEvents() - .forEach( - onEvents -> { - eventReferences.addAll(onEvents.getEventRefs()); - if (onEvents.getActions() != null) { - for (Action action : onEvents.getActions()) { - eventReferences.addAll(getActionEvents(action)); - } - } - }); - } - } else if (state instanceof OperationState) { - OperationState operationState = (OperationState) state; - if (operationState.getActions() != null) { - for (Action action : operationState.getActions()) { - eventReferences.addAll(getActionEvents(action)); - } - } - } else if (state instanceof ParallelState) { - ParallelState parallelState = (ParallelState) state; - if (parallelState.getBranches() != null) { - for (Branch branch : parallelState.getBranches()) { - if (branch.getActions() != null) { - for (Action action : branch.getActions()) { - eventReferences.addAll(getActionEvents(action)); - } - } - } - } - } - } - - return eventReferences.stream().distinct().collect(Collectors.toList()); - } - - /** - * @return Returns {@code int } Count of the workflow consumed events. Does not - * consider sub-workflows - */ - public static int getWorkflowConsumedEventsCount(Workflow workflow) { - List workflowConsumedEvents = getWorkflowConsumedEvents(workflow); - return workflowConsumedEvents == null ? 0 : workflowConsumedEvents.size(); - } - - /** - * @return Returns {@code int} Count of the workflow produced events. Does not - * consider sub-workflows in the count - */ - public static int getWorkflowProducedEventsCount(Workflow workflow) { - List workflowProducedEvents = getWorkflowProducedEvents(workflow); - return workflowProducedEvents == null ? 0 : workflowProducedEvents.size(); - } - - /** - * @return Returns function definition for actions - */ - public static FunctionDefinition getFunctionDefinitionsForAction( - Workflow workflow, String action) { - if (!hasFunctionDefs(workflow)) return null; - FunctionRef functionRef = getFunctionRefFromAction(workflow, action); - if (functionRef == null) return null; - final Optional functionDefinition = - workflow.getFunctions().getFunctionDefs().stream() - .filter(functionDef -> functionDef.getName().equals(functionRef.getRefName())) - .distinct() - .findFirst(); - - return functionDefinition.isPresent() ? functionDefinition.get() : null; - } - - /** - * @return : Returns @{code List} which uses a function defintion - */ - public static List getActionsForFunctionDefinition( - Workflow workflow, String functionDefinitionName) { - if (!hasFunctionDefs(workflow, functionDefinitionName)) return null; - return getActionsWhichUsesFunctionDefinition(workflow, functionDefinitionName); - } - - /** - * Gets Num of State in the workflow does not consider child workflow - * - * @param workflow - * @return - */ - public static long getNumOfStates(Workflow workflow) { - return hasStates(workflow) ? workflow.getStates().size() : DEFAULT_STATE_COUNT; - } - - /** - * Gets Num of States for State Type - * - * @param workflow - * @param type - * @return - */ - public static long getNumOfStates(Workflow workflow, DefaultState.Type type) { - return hasStates(workflow) - ? workflow.getStates().stream().filter(state -> state.getType() == type).count() - : DEFAULT_STATE_COUNT; - } - - /** - * Returns workflow state from provided name, or null if not found. - * - * @param workflow - * @param name - * @return - */ - public static State getStateWithName(Workflow workflow, String name) { - if (!hasStates(workflow)) { - return null; - } - - Optional state = - workflow.getStates().stream().filter(s -> s.getName().equals(name)).findFirst(); - - if (state.isPresent()) { - return state.get(); - } else { - return null; - } - } - - public static long getNumOfEndStates(Workflow workflow) { - if (hasStates(workflow)) { - long count = workflow.getStates().stream().filter(state -> state.getEnd() != null).count(); - List switchStates = - workflow.getStates().stream() - .filter(state -> state instanceof SwitchState) - .collect(Collectors.toList()); - for (State state : switchStates) { - SwitchState switchState = (SwitchState) state; - List eventConditions = switchState.getEventConditions(); - if (eventConditions != null) { - count = - count - + eventConditions.stream() - .filter(eventCondition -> eventCondition.getEnd() != null) - .count(); - } - List dataConditions = switchState.getDataConditions(); - if (dataConditions != null) { - count = - count - + dataConditions.stream() - .filter(dataCondition -> dataCondition.getEnd() != null) - .count(); - } - DefaultConditionDefinition defaultCondition = switchState.getDefaultCondition(); - if (defaultCondition != null) { - count = (defaultCondition.getEnd() != null) ? count + 1 : count; - } - } - return count; - } else { - return DEFAULT_STATE_COUNT; - } - } - - public static List getActionsWhichUsesFunctionDefinition( - Workflow workflow, String functionDefinitionName) { - List actions = new ArrayList<>(); - for (State state : workflow.getStates()) { - if (state instanceof EventState) { - EventState eventState = (EventState) state; - List onEvents = eventState.getOnEvents(); - if (onEvents != null) { - for (OnEvents onEvent : onEvents) { - if (onEvent != null) { - List onEventActions = onEvent.getActions(); - if (onEventActions != null) { - for (Action onEventAction : onEventActions) { - if (checkIfActionUsesFunctionDefinition(functionDefinitionName, onEventAction)) - actions.add(onEventAction); - } - } - } - } - } - } else if (state instanceof CallbackState) { - CallbackState callbackState = (CallbackState) state; - final Action callbackStateAction = callbackState.getAction(); - if (checkIfActionUsesFunctionDefinition(functionDefinitionName, callbackStateAction)) { - actions.add(callbackStateAction); - } - - } else if (state instanceof OperationState) { - OperationState operationState = (OperationState) state; - final List operationStateActions = operationState.getActions(); - if (operationStateActions != null) { - for (Action operationStateAction : operationStateActions) { - if (checkIfActionUsesFunctionDefinition(functionDefinitionName, operationStateAction)) { - actions.add(operationStateAction); - } - } - } - } else if (state instanceof ParallelState) { - ParallelState parallelState = (ParallelState) state; - List parallelStateBranches = parallelState.getBranches(); - if (parallelStateBranches != null) { - for (Branch branch : parallelStateBranches) { - List branchActions = branch.getActions(); - if (branchActions != null) { - for (Action branchAction : branchActions) { - if (checkIfActionUsesFunctionDefinition(functionDefinitionName, branchAction)) { - actions.add(branchAction); - } - } - } - } - } - } else if (state instanceof ForEachState) { - ForEachState forEachState = (ForEachState) state; - List forEachStateActions = forEachState.getActions(); - if (forEachStateActions != null) { - for (Action forEachStateAction : forEachStateActions) { - if (checkIfActionUsesFunctionDefinition(functionDefinitionName, forEachStateAction)) { - actions.add(forEachStateAction); - } - } - } - } - } - - return actions; - } - - public static boolean checkIfActionUsesFunctionDefinition( - String functionDefinitionName, Action action) { - return action != null - && action.getFunctionRef() != null - && action.getFunctionRef().getRefName() != null - && action.getFunctionRef().getRefName().equals(functionDefinitionName); - } - - public static boolean hasFunctionDefs(Workflow workflow, String functionDefinitionName) { - if (!hasFunctionDefs(workflow)) return false; - List functionDefs = workflow.getFunctions().getFunctionDefs(); - return functionDefs.stream() - .anyMatch( - functionDefinition -> functionDefinition.getName().equals(functionDefinitionName)); - } - - public static FunctionRef getFunctionRefFromAction(Workflow workflow, String action) { - if (!hasStates(workflow)) return null; - - for (State state : workflow.getStates()) { - if (state instanceof EventState) { - EventState eventState = (EventState) state; - List onEvents = eventState.getOnEvents(); - if (onEvents != null) { - for (OnEvents onEvent : onEvents) { - if (onEvent != null) { - List onEventActions = onEvent.getActions(); - if (onEventActions != null) { - for (Action onEventAction : onEventActions) { - if (onEventAction != null - && onEventAction.getName() != null - && onEventAction.getName().equals(action)) - return onEventAction.getFunctionRef(); - } - } - } - } - } - } else if (state instanceof CallbackState) { - CallbackState callbackState = (CallbackState) state; - final Action callbackStateAction = callbackState.getAction(); - if (callbackStateAction != null - && callbackStateAction.getName() != null - && callbackStateAction.getName().equals(action)) { - return callbackStateAction.getFunctionRef(); - } - - } else if (state instanceof OperationState) { - OperationState operationState = (OperationState) state; - final List operationStateActions = operationState.getActions(); - if (operationStateActions != null) { - for (Action operationStateAction : operationStateActions) { - if (operationStateAction != null - && operationStateAction.getName() != null - && operationStateAction.getName().equals(action)) { - return operationStateAction.getFunctionRef(); - } - } - } - } else if (state instanceof ParallelState) { - ParallelState parallelState = (ParallelState) state; - List parallelStateBranches = parallelState.getBranches(); - if (parallelStateBranches != null) { - for (Branch branch : parallelStateBranches) { - List branchActions = branch.getActions(); - if (branchActions != null) { - for (Action branchAction : branchActions) { - if (branchAction != null - && branchAction.getName() != null - && branchAction.getName().equals(action)) { - return branchAction.getFunctionRef(); - } - } - } - } - } - } else if (state instanceof ForEachState) { - ForEachState forEachState = (ForEachState) state; - List forEachStateActions = forEachState.getActions(); - if (forEachStateActions != null) { - for (Action forEachStateAction : forEachStateActions) { - if (forEachStateAction != null - && forEachStateAction.getName() != null - && forEachStateAction.getName().equals(action)) { - return forEachStateAction.getFunctionRef(); - } - } - } - } - } - - return null; - } - - public static boolean hasFunctionDefs(Workflow workflow) { - return workflow != null - && workflow.getFunctions() != null - && workflow.getFunctions().getFunctionDefs() != null - && !workflow.getFunctions().getFunctionDefs().isEmpty(); - } - - /** Returns true if workflow has states, otherwise false */ - public static boolean hasStates(Workflow workflow) { - return workflow != null && workflow.getStates() != null && !workflow.getStates().isEmpty(); - } - - /** Returns true if workflow has events definitions, otherwise false */ - public static boolean hasEventDefs(Workflow workflow) { - return workflow != null - && workflow.getEvents() != null - && workflow.getEvents().getEventDefs() != null - && !workflow.getEvents().getEventDefs().isEmpty(); - } - - /** Gets event refs of an action */ - public static List getActionEvents(Action action) { - List actionEvents = new ArrayList<>(); - - if (action != null && action.getEventRef() != null) { - if (action.getEventRef().getTriggerEventRef() != null) { - actionEvents.add(action.getEventRef().getTriggerEventRef()); - } - if (action.getEventRef().getResultEventRef() != null) { - actionEvents.add(action.getEventRef().getResultEventRef()); - } - } - - return actionEvents; - } - - /** - * Merges two JsonNode - * - * @param mainNode - * @param updateNode - * @return merged JsonNode - */ - public static JsonNode mergeNodes(JsonNode mainNode, JsonNode updateNode) { - - Iterator fieldNames = updateNode.fieldNames(); - while (fieldNames.hasNext()) { - - String fieldName = fieldNames.next(); - JsonNode jsonNode = mainNode.get(fieldName); - // if field exists and is an embedded object - if (jsonNode != null && jsonNode.isObject()) { - mergeNodes(jsonNode, updateNode.get(fieldName)); - } else { - if (mainNode instanceof ObjectNode) { - // Overwrite field - JsonNode value = updateNode.get(fieldName); - ((ObjectNode) mainNode).set(fieldName, value); - } - } - } - - return mainNode; - } - - /** - * Adds node as field - * - * @param mainNode - * @param toAddNode - * @param fieldName - * @return original, main node with field added - */ - public static JsonNode addNode(JsonNode mainNode, JsonNode toAddNode, String fieldName) { - ((ObjectNode) mainNode).set(fieldName, toAddNode); - return mainNode; - } - - /** - * Adds array with name - * - * @param mainNode - * @param toAddArray - * @param arrayName - * @return original, main node with array added - */ - public static JsonNode addArray(JsonNode mainNode, ArrayNode toAddArray, String arrayName) { - ((ObjectNode) mainNode).set(arrayName, toAddArray); - return mainNode; - } - - /** - * Adds a object field - * - * @param mainNode - * @param toAddValue - * @param fieldName - * @return original, main node with field added - */ - public static JsonNode addFieldValue(JsonNode mainNode, Object toAddValue, String fieldName) { - ObjectMapper mapper = new ObjectMapper(); - ((ObjectNode) mainNode).set(fieldName, mapper.valueToTree(toAddValue)); - return mainNode; - } - - /** - * Returns a list of function definitions that have the given type. - * - * @param workflow - * @param type - * @return list of functions defs or null - */ - public static List getFunctionDefinitionsWithType( - Workflow workflow, FunctionDefinition.Type type) { - if (!hasFunctionDefs(workflow)) return null; - return workflow.getFunctions().getFunctionDefs().stream() - .filter(fd -> fd.getType().equals(type)) - .collect(Collectors.toList()); - } - - /** - * Returns function definition with provided name - * - * @param workflow - * @param name - * @return function definition or null - */ - public static FunctionDefinition getFunctionDefinitionWithName(Workflow workflow, String name) { - if (!hasFunctionDefs(workflow)) return null; - Optional funcDef = - workflow.getFunctions().getFunctionDefs().stream() - .filter(fd -> fd.getName().equals(name)) - .findFirst(); - return funcDef.orElse(null); - } -} diff --git a/utils/src/test/java/io/serverlessworkflow/util/DefinedEventsTest.java b/utils/src/test/java/io/serverlessworkflow/util/DefinedEventsTest.java deleted file mode 100644 index 2e480dba..00000000 --- a/utils/src/test/java/io/serverlessworkflow/util/DefinedEventsTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.serverlessworkflow.util; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.util.testutil.TestUtils; -import io.serverlessworkflow.utils.WorkflowUtils; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -class DefinedEventsTest { - @ParameterizedTest - @ValueSource(strings = {"/events/workflowwithevents.yml"}) - public void testGetDefinedConsumedEvents(String workflowEvents) { - int consumedEventsCount = 2; - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowEvents); - List consumedEvents = WorkflowUtils.getDefinedConsumedEvents(workflow); - assertEquals(consumedEventsCount, consumedEvents.size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/events/workflowwithevents.yml"}) - public void testGetDefinedroducedEvents(String workflowEvents) { - int producedEventsCounts = 1; - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowEvents); - List producedEvents = WorkflowUtils.getDefinedProducedEvents(workflow); - assertEquals(producedEventsCounts, producedEvents.size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/events/workflowwithevents.yml"}) - public void testGetDefinedConsumedEventsCount(String workflowEvents) { - int consumedEventsCountExpected = 2; - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowEvents); - int consumedEventsCount = WorkflowUtils.getDefinedConsumedEventsCount(workflow); - assertEquals(consumedEventsCountExpected, consumedEventsCount); - } - - @ParameterizedTest - @ValueSource(strings = {"/events/workflowwithevents.yml"}) - public void testGetDefinedroducedEventsCount(String workflowEvents) { - int producedEventsCountExpected = 1; - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowEvents); - int producedEventsCount = WorkflowUtils.getDefinedProducedEventsCount(workflow); - assertEquals(producedEventsCountExpected, producedEventsCount); - } - - @Test - public void testGetDefinedEventsForNullWorkflow() { - assertNull(WorkflowUtils.getDefinedEvents(null, EventDefinition.Kind.CONSUMED)); - } - - @Test - public void testGetDefinedEventsCountForNullWorkflow() { - int expectedCount = 0; - assertEquals( - expectedCount, WorkflowUtils.getDefinedEventsCount(null, EventDefinition.Kind.PRODUCED)); - } -} diff --git a/utils/src/test/java/io/serverlessworkflow/util/EventsTest.java b/utils/src/test/java/io/serverlessworkflow/util/EventsTest.java deleted file mode 100644 index ab0c2413..00000000 --- a/utils/src/test/java/io/serverlessworkflow/util/EventsTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.serverlessworkflow.util; - -import static org.junit.jupiter.api.Assertions.*; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.util.testutil.TestUtils; -import io.serverlessworkflow.utils.WorkflowUtils; -import java.util.*; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -public class EventsTest { - @ParameterizedTest - @ValueSource(strings = {"/events/workflowwithevents.yml"}) - public void testGetConsumedEvents(String workflowEvents) { - int expectedEventsCount = 2; - Collection expectedConsumedEvent = - Arrays.asList("SATScoresReceived", "RecommendationLetterReceived"); - Set uniqueExpectedConsumedEvent = new HashSet<>(expectedConsumedEvent); - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowEvents); - List consumedEvents = WorkflowUtils.getWorkflowConsumedEvents(workflow); - assertEquals(expectedEventsCount, consumedEvents.size()); - for (EventDefinition consumedEvent : consumedEvents) { - assertTrue(uniqueExpectedConsumedEvent.contains(consumedEvent.getName())); - } - } - - @ParameterizedTest - @ValueSource(strings = {"/events/workflowwithevents.yml"}) - public void testGetConsumedEventsCount(String workflowEvents) { - int expectedEventsCount = 2; - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowEvents); - int workflowConsumedEventsCount = WorkflowUtils.getWorkflowConsumedEventsCount(workflow); - Arrays.asList(expectedEventsCount, workflowConsumedEventsCount); - } - - @ParameterizedTest - @ValueSource(strings = {"/events/workflowwithproducedevents.yml"}) - public void testGetWorkflowProducedEvents(String workflowProducedEvents) { - int expectedEventsCount = 1; - Collection expectedProducedEvent = Arrays.asList("ApplicationSubmitted"); - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowProducedEvents); - List producedEvents = WorkflowUtils.getWorkflowProducedEvents(workflow); - assertNotNull(producedEvents); - assertEquals(expectedEventsCount, producedEvents.size()); - for (EventDefinition producedEvent : producedEvents) { - assertTrue(expectedProducedEvent.contains(producedEvent.getName())); - } - } - - @ParameterizedTest - @ValueSource(strings = {"/events/workflowwithproducedevents.yml"}) - public void testGetWorkflowProducedEventsCount(String workflowProducedEvents) { - int expectedEventsCount = 1; - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowProducedEvents); - int producedEventsCount = WorkflowUtils.getWorkflowProducedEventsCount(workflow); - assertEquals(expectedEventsCount, producedEventsCount); - } -} diff --git a/utils/src/test/java/io/serverlessworkflow/util/FunctionDefinitionsTest.java b/utils/src/test/java/io/serverlessworkflow/util/FunctionDefinitionsTest.java deleted file mode 100644 index 14b00bcc..00000000 --- a/utils/src/test/java/io/serverlessworkflow/util/FunctionDefinitionsTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.serverlessworkflow.util; - -import static org.junit.jupiter.api.Assertions.*; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.actions.Action; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.util.testutil.TestUtils; -import io.serverlessworkflow.utils.WorkflowUtils; -import java.util.List; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -public class FunctionDefinitionsTest { - - @ParameterizedTest - @ValueSource(strings = {"/funcdefinitiontest/functiondefinition.yml"}) - public void testFunctionDefsForAction(String funcDefinitions) { - String actionLookUp = "finalizeApplicationAction"; - String expectedFunctionRefName = "finalizeApplicationFunction"; - Workflow workflow = TestUtils.createWorkflowFromTestResource(funcDefinitions); - FunctionDefinition finalizeApplicationFunctionDefinition = - WorkflowUtils.getFunctionDefinitionsForAction(workflow, actionLookUp); - assertNotNull(finalizeApplicationFunctionDefinition); - assertEquals(expectedFunctionRefName, finalizeApplicationFunctionDefinition.getName()); - } - - @ParameterizedTest - @ValueSource(strings = {"/funcdefinitiontest/functiondefinition.yml"}) - public void testFunctionDefsForActionNotPresent(String funcDefinitions) { - String actionLookUp = "finalizeApplicationFunctionNotPresent"; - Workflow workflow = TestUtils.createWorkflowFromTestResource(funcDefinitions); - FunctionDefinition finalizeApplicationFunctionDefinition = - WorkflowUtils.getFunctionDefinitionsForAction(workflow, actionLookUp); - assertNull(finalizeApplicationFunctionDefinition); - } - - @ParameterizedTest - @ValueSource(strings = {"/funcdefinitiontest/functiondefinition.yml"}) - public void testFunctionDefsForNullWorkflow(String funcDefinitions) { - assertNull(WorkflowUtils.getFunctionDefinitionsForAction(null, "TestAction")); - } - - @ParameterizedTest - @ValueSource(strings = {"/funcdefinitiontest/functiondefinition.yml"}) - public void testGetActionsForFunctionDefinition(String funcDefinitions) { - String functionRefName = "finalizeApplicationFunction"; - int expectedActionCount = 2; - Workflow workflow = TestUtils.createWorkflowFromTestResource(funcDefinitions); - List actionsForFunctionDefinition = - WorkflowUtils.getActionsForFunctionDefinition(workflow, functionRefName); - assertEquals(expectedActionCount, actionsForFunctionDefinition.size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/funcdefinitiontest/functiondefinition.yml"}) - public void testGetFunctionDefinitionWithName(String funcDefinitions) { - Workflow workflow = TestUtils.createWorkflowFromTestResource(funcDefinitions); - assertNotNull( - WorkflowUtils.getFunctionDefinitionWithName(workflow, "finalizeApplicationFunction")); - } -} diff --git a/utils/src/test/java/io/serverlessworkflow/util/FunctionsWithTypeTest.java b/utils/src/test/java/io/serverlessworkflow/util/FunctionsWithTypeTest.java deleted file mode 100644 index ab30aece..00000000 --- a/utils/src/test/java/io/serverlessworkflow/util/FunctionsWithTypeTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.serverlessworkflow.util; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.util.testutil.TestUtils; -import io.serverlessworkflow.utils.WorkflowUtils; -import java.util.List; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -public class FunctionsWithTypeTest { - @ParameterizedTest - @ValueSource(strings = {"/functiontypes/workflowfunctiontypes.yml"}) - public void testGetNumStates(String workflowWithStates) { - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowWithStates); - List expressionFunctionDefs = - WorkflowUtils.getFunctionDefinitionsWithType(workflow, FunctionDefinition.Type.EXPRESSION); - assertNotNull(expressionFunctionDefs); - assertEquals(2, expressionFunctionDefs.size()); - assertEquals("Function One", expressionFunctionDefs.get(0).getName()); - assertEquals("Function Three", expressionFunctionDefs.get(1).getName()); - } -} diff --git a/utils/src/test/java/io/serverlessworkflow/util/GetNumTests.java b/utils/src/test/java/io/serverlessworkflow/util/GetNumTests.java deleted file mode 100644 index 1a2827a4..00000000 --- a/utils/src/test/java/io/serverlessworkflow/util/GetNumTests.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.serverlessworkflow.util; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.util.testutil.TestUtils; -import io.serverlessworkflow.utils.WorkflowUtils; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -public class GetNumTests { - @ParameterizedTest - @ValueSource(strings = {"/getStates/workflowwithstates.yml"}) - public void testGetNumStates(String workflowWithStates) { - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowWithStates); - int expectedStatesCount = 2; - assertEquals(expectedStatesCount, WorkflowUtils.getNumOfStates(workflow)); - } - - @ParameterizedTest - @ValueSource(strings = {"/start/workflowwithnostate.yml"}) - public void testGetNumStatesForNoStateInWorkflow(String workflowWithStates) { - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowWithStates); - int expectedStatesCount = 0; - assertEquals(expectedStatesCount, WorkflowUtils.getNumOfStates(workflow)); - } - - @ParameterizedTest - @ValueSource(strings = {"/getStates/workflowwithstates.yml"}) - public void testGetNumStatesOfEventType(String workflowWithStates) { - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowWithStates); - int expectedStatesCount = 2; - assertEquals( - expectedStatesCount, WorkflowUtils.getNumOfStates(workflow, DefaultState.Type.EVENT)); - } - - @ParameterizedTest - @ValueSource(strings = {"/events/workflowwithevents.yml"}) - public void testGetNumEndStates(String workflowWithStates) { - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowWithStates); - int expectedEndStatesCount = 2; - assertEquals(expectedEndStatesCount, WorkflowUtils.getNumOfEndStates(workflow)); - } -} diff --git a/utils/src/test/java/io/serverlessworkflow/util/GetStatesTest.java b/utils/src/test/java/io/serverlessworkflow/util/GetStatesTest.java deleted file mode 100644 index 7d977251..00000000 --- a/utils/src/test/java/io/serverlessworkflow/util/GetStatesTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.serverlessworkflow.util; - -import static org.junit.jupiter.api.Assertions.*; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.states.DefaultState; -import io.serverlessworkflow.api.states.EventState; -import io.serverlessworkflow.util.testutil.TestUtils; -import io.serverlessworkflow.utils.WorkflowUtils; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -class GetStatesTest { - - @ParameterizedTest - @ValueSource(strings = {"/getStates/workflowwithstates.yml"}) - public void testGetStatesByDefaultState(String workflowWithState) { - int matchingEvents = 2; - int notMatchingEvents = 0; - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowWithState); - List matchingStates = WorkflowUtils.getStates(workflow, DefaultState.Type.EVENT); - List notMatchingStates = WorkflowUtils.getStates(workflow, DefaultState.Type.SLEEP); - assertEquals(matchingEvents, matchingStates.size()); - assertEquals(notMatchingEvents, notMatchingStates.size()); - } - - @ParameterizedTest - @ValueSource(strings = {"/getStates/workflowwithstates.yml"}) - public void testGetStateByName(String workflowWithState) { - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowWithState); - - State finalizeApplicationState = - WorkflowUtils.getStateWithName(workflow, "FinalizeApplication"); - assertNotNull(finalizeApplicationState); - assertTrue(finalizeApplicationState instanceof EventState); - - State cancelApplicationState = WorkflowUtils.getStateWithName(workflow, "CancelApplication"); - assertNotNull(cancelApplicationState); - assertTrue(cancelApplicationState instanceof EventState); - } - - @Test - public void testGetsStatesForNullWorkflow() { - assertNull(WorkflowUtils.getStates(null, DefaultState.Type.EVENT)); - } -} diff --git a/utils/src/test/java/io/serverlessworkflow/util/JsonManipulationTest.java b/utils/src/test/java/io/serverlessworkflow/util/JsonManipulationTest.java deleted file mode 100644 index 9673e689..00000000 --- a/utils/src/test/java/io/serverlessworkflow/util/JsonManipulationTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.util; - -import static org.junit.jupiter.api.Assertions.*; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import io.serverlessworkflow.utils.WorkflowUtils; -import org.junit.jupiter.api.Test; - -public class JsonManipulationTest { - private static final ObjectMapper mapper = new ObjectMapper(); - - @Test - public void testAddFieldValue() throws Exception { - String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}"; - JsonNode mainNode = mapper.readTree(mainString); - String toAddString = "v3"; - - JsonNode added = WorkflowUtils.addFieldValue(mainNode, toAddString, "k3"); - - assertNotNull(added); - assertEquals("v3", added.get("k3").asText()); - } - - @Test - public void testAddNode() throws Exception { - String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}"; - JsonNode mainNode = mapper.readTree(mainString); - String toAddString = "{\"k3\":\"v3\"}"; - JsonNode toAddNode = mapper.readTree(toAddString); - - JsonNode added = WorkflowUtils.addNode(mainNode, toAddNode, "newnode"); - - assertNotNull(added); - assertEquals("v3", added.get("newnode").get("k3").asText()); - } - - @Test - public void testAddArray() throws Exception { - String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}"; - JsonNode mainNode = mapper.readTree(mainString); - String toAddString = "[\"a\", \"b\"]"; - JsonNode toAddNode = mapper.readTree(toAddString); - - JsonNode added = WorkflowUtils.addArray(mainNode, (ArrayNode) toAddNode, "newarray"); - - assertNotNull(added); - assertNotNull(added.get("newarray")); - assertEquals(2, added.get("newarray").size()); - assertEquals("a", added.get("newarray").get(0).asText()); - assertEquals("b", added.get("newarray").get(1).asText()); - } - - @Test - public void testMergeNodes() throws Exception { - String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}"; - JsonNode mainNode = mapper.readTree(mainString); - String toMergeString = "{\"k3\":\"v3\",\"k4\":\"v4\"}"; - JsonNode toMergeNode = mapper.readTree(toMergeString); - - JsonNode merged = WorkflowUtils.mergeNodes(mainNode, toMergeNode); - - assertNotNull(merged); - assertEquals("v3", merged.get("k3").asText()); - assertEquals("v4", merged.get("k4").asText()); - } - - @Test - public void testMergeWithOverwrite() throws Exception { - String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}"; - JsonNode mainNode = mapper.readTree(mainString); - String toMergeString = "{\"k2\":\"v2new\",\"k3\":\"v3\"}"; - JsonNode toMergeNode = mapper.readTree(toMergeString); - - JsonNode merged = WorkflowUtils.mergeNodes(mainNode, toMergeNode); - - assertNotNull(merged); - assertEquals("v2new", merged.get("k2").asText()); - assertEquals("v3", merged.get("k3").asText()); - } -} diff --git a/utils/src/test/java/io/serverlessworkflow/util/StartStateTest.java b/utils/src/test/java/io/serverlessworkflow/util/StartStateTest.java deleted file mode 100644 index aad5de7f..00000000 --- a/utils/src/test/java/io/serverlessworkflow/util/StartStateTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.serverlessworkflow.util; - -import static org.junit.jupiter.api.Assertions.*; - -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.util.testutil.TestUtils; -import io.serverlessworkflow.utils.WorkflowUtils; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -class StartStateTest { - - @ParameterizedTest - @ValueSource(strings = {"/start/workflowwithstartstate.yml"}) - public void testGetStartState(String workflowWithStartState) { - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowWithStartState); - State startingState = WorkflowUtils.getStartingState(workflow); - assertNotNull(startingState); - assertEquals(startingState.getName(), workflow.getStart().getStateName()); - } - - @ParameterizedTest - @ValueSource(strings = {"/start/workflowwithstartnotspecified.yml"}) - public void testGetStartStateForWorkflowWithStartNotSpecified( - String workflowWithStartStateNotSpecified) { - Workflow workflow = - TestUtils.createWorkflowFromTestResource(workflowWithStartStateNotSpecified); - State startingState = WorkflowUtils.getStartingState(workflow); - assertEquals(workflow.getStates().get(0).getName(), startingState.getName()); - } - - @ParameterizedTest - @ValueSource(strings = {"/start/workflowwithnostate.yml"}) - public void testGetStartStateForWorkflowWithNoState(String workflowWithNoState) { - Workflow workflow = TestUtils.createWorkflowFromTestResource(workflowWithNoState); - State startingState = WorkflowUtils.getStartingState(workflow); - assertNull(startingState); - } - - @Test - public void testGetStateForNullWorkflow() { - State startingState = WorkflowUtils.getStartingState(null); - assertNull(startingState); - } -} diff --git a/utils/src/test/java/io/serverlessworkflow/util/testutil/TestUtils.java b/utils/src/test/java/io/serverlessworkflow/util/testutil/TestUtils.java deleted file mode 100644 index c4c59820..00000000 --- a/utils/src/test/java/io/serverlessworkflow/util/testutil/TestUtils.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.util.testutil; - -import io.serverlessworkflow.api.Workflow; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; - -public class TestUtils { - - public static Workflow createWorkflow(String source) { - return Workflow.fromSource(source); - } - - public static Workflow createWorkflowFromTestResource(String fileRelativePath) { - InputStreamReader reader = getTestResourceStreamReader(fileRelativePath); - return createWorkflow(readFileAsString(reader)); - } - - public static String readFileAsString(Reader reader) { - try { - StringBuilder fileData = new StringBuilder(1000); - char[] buf = new char[1024]; - int numRead; - while ((numRead = reader.read(buf)) != -1) { - String readData = String.valueOf(buf, 0, numRead); - fileData.append(readData); - buf = new char[1024]; - } - reader.close(); - return fileData.toString(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static InputStreamReader getTestResourceStreamReader(String fileRelativePath) { - return new InputStreamReader(TestUtils.class.getResourceAsStream(fileRelativePath)); - } -} diff --git a/utils/src/test/resources/events/workflowwithevents.yml b/utils/src/test/resources/events/workflowwithevents.yml deleted file mode 100644 index 211b53e2..00000000 --- a/utils/src/test/resources/events/workflowwithevents.yml +++ /dev/null @@ -1,56 +0,0 @@ -id: finalizeCollegeApplication -name: Finalize College Application -version: '1.0' -specVersion: '0.8' -events: - - name: ApplicationSubmitted - type: org.application.submitted - source: applicationsource - kind: produced - correlation: - - contextAttributeName: applicantId - - name: SATScoresReceived - type: org.application.satscores - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: RecommendationLetterReceived - type: org.application.recommendationLetter - source: applicationsource - correlation: - - contextAttributeName: applicantId -functions: - - name: finalizeApplicationFunction - operation: http://myapis.org/collegeapplicationapi.json#finalize -states: - - name: FinalizeApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true - - - name: CancelApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true \ No newline at end of file diff --git a/utils/src/test/resources/events/workflowwithproducedevents.yml b/utils/src/test/resources/events/workflowwithproducedevents.yml deleted file mode 100644 index 8cd80895..00000000 --- a/utils/src/test/resources/events/workflowwithproducedevents.yml +++ /dev/null @@ -1,59 +0,0 @@ -id: finalizeCollegeApplication -name: Finalize College Application -version: '1.0' -specVersion: '0.8' -events: - - name: ApplicationSubmitted - type: org.application.submitted - source: applicationsource - kind: produced - correlation: - - contextAttributeName: applicantId - - name: SATScoresReceived - type: org.application.satscores - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: RecommendationLetterReceived - type: org.application.recommendationLetter - source: applicationsource - correlation: - - contextAttributeName: applicantId -functions: - - name: finalizeApplicationFunction - operation: http://myapis.org/collegeapplicationapi.json#finalize -states: - - name: FinalizeApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true - produceEvents: - - eventRef: ApplicationSubmitted - data: "${ .provisionedOrders }" - - - name: CancelApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true \ No newline at end of file diff --git a/utils/src/test/resources/funcdefinitiontest/functiondefinition.yml b/utils/src/test/resources/funcdefinitiontest/functiondefinition.yml deleted file mode 100644 index 7ad953a7..00000000 --- a/utils/src/test/resources/funcdefinitiontest/functiondefinition.yml +++ /dev/null @@ -1,58 +0,0 @@ -id: finalizeCollegeApplication -name: Finalize College Application -version: '1.0' -specVersion: '0.8' -events: - - name: ApplicationSubmitted - type: org.application.submitted - source: applicationsource - kind: produced - correlation: - - contextAttributeName: applicantId - - name: SATScoresReceived - type: org.application.satscores - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: RecommendationLetterReceived - type: org.application.recommendationLetter - source: applicationsource - correlation: - - contextAttributeName: applicantId -functions: - - name: finalizeApplicationFunction - operation: http://myapis.org/collegeapplicationapi.json#finalize -states: - - name: FinalizeApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - name : finalizeApplicationAction - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true - - - name: CancelApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - name : finalizeApplicationAction - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true \ No newline at end of file diff --git a/utils/src/test/resources/functiontypes/workflowfunctiontypes.yml b/utils/src/test/resources/functiontypes/workflowfunctiontypes.yml deleted file mode 100644 index a205f469..00000000 --- a/utils/src/test/resources/functiontypes/workflowfunctiontypes.yml +++ /dev/null @@ -1,22 +0,0 @@ -id: functiontypes -version: '1.0' -specVersion: '0.8' -name: Function Types Workflow -functions: - - name: Function One - type: expression - operation: ".one" - - name: Function Two - type: asyncapi - operation: banking.yaml#largerTransation - - name: Function Three - type: expression - operation: ".three" -states: - - name: Dummy - type: operation - actions: - - functionRef: Function One - - functionRef: Function Two - - functionRef: Function Three - end: true diff --git a/utils/src/test/resources/getStates/workflowwithstates.yml b/utils/src/test/resources/getStates/workflowwithstates.yml deleted file mode 100644 index 9ac1edb5..00000000 --- a/utils/src/test/resources/getStates/workflowwithstates.yml +++ /dev/null @@ -1,55 +0,0 @@ -id: finalizeCollegeApplication -name: Finalize College Application -version: '1.0' -specVersion: '0.8' -events: - - name: ApplicationSubmitted - type: org.application.submitted - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: SATScoresReceived - type: org.application.satscores - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: RecommendationLetterReceived - type: org.application.recommendationLetter - source: applicationsource - correlation: - - contextAttributeName: applicantId -functions: - - name: finalizeApplicationFunction - operation: http://myapis.org/collegeapplicationapi.json#finalize -states: - - name: FinalizeApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true - - - name: CancelApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true \ No newline at end of file diff --git a/utils/src/test/resources/start/workflowwithnostate.yml b/utils/src/test/resources/start/workflowwithnostate.yml deleted file mode 100644 index a16e68df..00000000 --- a/utils/src/test/resources/start/workflowwithnostate.yml +++ /dev/null @@ -1,24 +0,0 @@ -id: finalizeCollegeApplication -name: Finalize College Application -version: '1.0' -specVersion: '0.8' -start: FinalizeApplication -events: - - name: ApplicationSubmitted - type: org.application.submitted - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: SATScoresReceived - type: org.application.satscores - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: RecommendationLetterReceived - type: org.application.recommendationLetter - source: applicationsource - correlation: - - contextAttributeName: applicantId -functions: - - name: finalizeApplicationFunction - operation: http://myapis.org/collegeapplicationapi.json#finalize diff --git a/utils/src/test/resources/start/workflowwithstartnotspecified.yml b/utils/src/test/resources/start/workflowwithstartnotspecified.yml deleted file mode 100644 index 03bb87c5..00000000 --- a/utils/src/test/resources/start/workflowwithstartnotspecified.yml +++ /dev/null @@ -1,39 +0,0 @@ -id: finalizeCollegeApplication -name: Finalize College Application -version: '1.0' -specVersion: '0.8' -events: - - name: ApplicationSubmitted - type: org.application.submitted - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: SATScoresReceived - type: org.application.satscores - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: RecommendationLetterReceived - type: org.application.recommendationLetter - source: applicationsource - correlation: - - contextAttributeName: applicantId -functions: - - name: finalizeApplicationFunction - operation: http://myapis.org/collegeapplicationapi.json#finalize -states: - - name: FinalizeApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true \ No newline at end of file diff --git a/utils/src/test/resources/start/workflowwithstartstate.yml b/utils/src/test/resources/start/workflowwithstartstate.yml deleted file mode 100644 index 0d2fd30c..00000000 --- a/utils/src/test/resources/start/workflowwithstartstate.yml +++ /dev/null @@ -1,40 +0,0 @@ -id: finalizeCollegeApplication -name: Finalize College Application -version: '1.0' -specVersion: '0.8' -start: FinalizeApplication -events: - - name: ApplicationSubmitted - type: org.application.submitted - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: SATScoresReceived - type: org.application.satscores - source: applicationsource - correlation: - - contextAttributeName: applicantId - - name: RecommendationLetterReceived - type: org.application.recommendationLetter - source: applicationsource - correlation: - - contextAttributeName: applicantId -functions: - - name: finalizeApplicationFunction - operation: http://myapis.org/collegeapplicationapi.json#finalize -states: - - name: FinalizeApplication - type: event - exclusive: false - onEvents: - - eventRefs: - - ApplicationSubmitted - - SATScoresReceived - - RecommendationLetterReceived - actions: - - functionRef: - refName: finalizeApplicationFunction - arguments: - student: "${ .applicantId }" - end: - terminate: true \ No newline at end of file diff --git a/validation/.gitignore b/validation/.gitignore deleted file mode 100644 index d4dfde66..00000000 --- a/validation/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/** -!**/src/test/** - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ - -### VS Code ### -.vscode/ \ No newline at end of file diff --git a/validation/pom.xml b/validation/pom.xml deleted file mode 100644 index 71a32ff2..00000000 --- a/validation/pom.xml +++ /dev/null @@ -1,146 +0,0 @@ - - 4.0.0 - - - io.serverlessworkflow - serverlessworkflow-parent - 7.0.0-SNAPSHOT - - - serverlessworkflow-validation - Serverless Workflow :: Validation - jar - Java SDK for Serverless Workflow Specification - - - - org.slf4j - slf4j-api - - - org.slf4j - jcl-over-slf4j - - - - io.serverlessworkflow - serverlessworkflow-api - ${project.version} - - - - org.apache.commons - commons-lang3 - - - com.networknt - json-schema-validator - - - - org.junit.jupiter - junit-jupiter-api - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.junit.jupiter - junit-jupiter-params - test - - - org.mockito - mockito-core - test - - - ch.qos.logback - logback-classic - test - - - org.assertj - assertj-core - test - - - org.hamcrest - hamcrest-library - test - - - org.skyscreamer - jsonassert - test - - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - - - - - - - - - - - - ${project.build.directory}/checkstyle.log - true - true - true - false - false - ${checkstyle.logViolationsToConsole} - ${checkstyle.failOnViolation} - - ${project.build.sourceDirectory} - ${project.build.testSourceDirectory} - - - - - compile - - check - - - - - - com.spotify.fmt - fmt-maven-plugin - - src/main/java - src/test/java - false - .*\.java - false - false - - - - - - format - - - - - - - diff --git a/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java b/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java deleted file mode 100644 index c7b7336f..00000000 --- a/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.validation; - -import com.fasterxml.jackson.databind.JsonNode; -import com.networknt.schema.JsonSchemaFactory; -import com.networknt.schema.SpecVersion.VersionFlag; -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.actions.Action; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.api.events.OnEvents; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.interfaces.State; -import io.serverlessworkflow.api.interfaces.WorkflowValidator; -import io.serverlessworkflow.api.retry.RetryDefinition; -import io.serverlessworkflow.api.states.*; -import io.serverlessworkflow.api.switchconditions.DataCondition; -import io.serverlessworkflow.api.switchconditions.EventCondition; -import io.serverlessworkflow.api.utils.Utils; -import io.serverlessworkflow.api.validation.ValidationError; -import io.serverlessworkflow.api.validation.WorkflowSchemaLoader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class WorkflowValidatorImpl implements WorkflowValidator { - - private static final Logger logger = LoggerFactory.getLogger(WorkflowValidatorImpl.class); - private boolean schemaValidationEnabled = true; - private final List validationErrors = new ArrayList<>(); - private final JsonNode workflowSchema = WorkflowSchemaLoader.getWorkflowSchema(); - private String source; - private Workflow workflow; - - @Override - public WorkflowValidator setWorkflow(Workflow workflow) { - this.workflow = workflow; - return this; - } - - @Override - public WorkflowValidator setSource(String source) { - this.source = source; - return this; - } - - @Override - public List validate() { - validationErrors.clear(); - if (workflow == null) { - try { - if (schemaValidationEnabled && source != null) { - JsonSchemaFactory.getInstance(VersionFlag.V7) - .getSchema(workflowSchema) - .validate(Utils.getNode(source)) - .forEach(m -> addValidationError(m.getMessage(), ValidationError.SCHEMA_VALIDATION)); - } - } catch (IOException e) { - logger.error("Unexpected error during validation", e); - } - } - - // if there are schema validation errors - // there is no point of doing the workflow validation - if (!validationErrors.isEmpty()) { - return validationErrors; - } else if (workflow == null) { - workflow = Workflow.fromSource(source); - } - - List functions = - workflow.getFunctions() != null ? workflow.getFunctions().getFunctionDefs() : null; - - List events = - workflow.getEvents() != null ? workflow.getEvents().getEventDefs() : null; - - if ((workflow.getId() == null || workflow.getId().trim().isEmpty()) - && (workflow.getKey() == null || workflow.getKey().trim().isEmpty())) { - addValidationError( - "Workflow id or key should not be empty", ValidationError.WORKFLOW_VALIDATION); - } - - if (workflow.getVersion() == null || workflow.getVersion().trim().isEmpty()) { - addValidationError( - "Workflow version should not be empty", ValidationError.WORKFLOW_VALIDATION); - } - - if (workflow.getRetries() != null && workflow.getRetries().getRetryDefs() != null) { - workflow - .getRetries() - .getRetryDefs() - .forEach( - r -> { - if (r.getName() == null || r.getName().isEmpty()) { - addValidationError( - "Retry name should not be empty", ValidationError.WORKFLOW_VALIDATION); - } - }); - } - - if (workflow.getStates() == null || workflow.getStates().isEmpty()) { - addValidationError("No states found", ValidationError.WORKFLOW_VALIDATION); - } - - if (workflow.getStates() != null && !workflow.getStates().isEmpty()) { - boolean existingStateWithStartProperty = false; - if (workflow.getStart() != null) { - String startProperty = workflow.getStart().getStateName(); - for (State s : workflow.getStates()) { - if (s.getName().equals(startProperty)) { - existingStateWithStartProperty = true; - break; - } - } - } else { - existingStateWithStartProperty = true; - } - if (!existingStateWithStartProperty) { - addValidationError( - "No state name found that matches the workflow start definition", - ValidationError.WORKFLOW_VALIDATION); - } - } - - Validation validation = new Validation(); - if (workflow.getStates() != null && !workflow.getStates().isEmpty()) { - workflow - .getStates() - .forEach( - s -> { - if (s.getName() != null && s.getName().trim().isEmpty()) { - addValidationError( - "State name should not be empty", ValidationError.WORKFLOW_VALIDATION); - } else { - validation.addState(s.getName()); - } - - if (s.getEnd() != null) { - validation.addEndState(); - } - - if (s instanceof OperationState) { - OperationState operationState = (OperationState) s; - checkActionsDefinition(operationState.getActions(), functions, events); - } - - if (s instanceof EventState) { - EventState eventState = (EventState) s; - if (eventState.getOnEvents() == null || eventState.getOnEvents().isEmpty()) { - addValidationError( - "Event State has no eventActions defined", - ValidationError.WORKFLOW_VALIDATION); - } - List eventsActionsList = eventState.getOnEvents(); - for (OnEvents onEvents : eventsActionsList) { - - List eventRefs = onEvents.getEventRefs(); - if (eventRefs == null || eventRefs.isEmpty()) { - addValidationError( - "Event State eventsActions has no event refs", - ValidationError.WORKFLOW_VALIDATION); - } else { - for (String eventRef : eventRefs) { - if (isMissingEventsDefinition(eventRef, events)) { - addValidationError( - "Event State eventsActions eventRef does not match a declared workflow event definition", - ValidationError.WORKFLOW_VALIDATION); - } - } - } - } - } - - if (s instanceof SwitchState) { - SwitchState switchState = (SwitchState) s; - if ((switchState.getDataConditions() == null - || switchState.getDataConditions().isEmpty()) - && (switchState.getEventConditions() == null - || switchState.getEventConditions().isEmpty())) { - addValidationError( - "Switch state should define either data or event conditions", - ValidationError.WORKFLOW_VALIDATION); - } - - if (switchState.getDefaultCondition() == null) { - addValidationError( - "Switch state should define a default transition", - ValidationError.WORKFLOW_VALIDATION); - } - - if (switchState.getEventConditions() != null - && !switchState.getEventConditions().isEmpty()) { - List eventConditions = switchState.getEventConditions(); - for (EventCondition ec : eventConditions) { - if (isMissingEventsDefinition(ec.getEventRef(), events)) { - addValidationError( - "Switch state event condition eventRef does not reference a defined workflow event", - ValidationError.WORKFLOW_VALIDATION); - } - if (ec.getEnd() != null) { - validation.addEndState(); - } - } - } - - if (switchState.getDataConditions() != null - && !switchState.getDataConditions().isEmpty()) { - List dataConditions = switchState.getDataConditions(); - for (DataCondition dc : dataConditions) { - if (dc.getEnd() != null) { - validation.addEndState(); - } - } - } - } - - if (s instanceof SleepState) { - SleepState sleepState = (SleepState) s; - if (sleepState.getDuration() == null || sleepState.getDuration().isEmpty()) { - addValidationError( - "Sleep state should have a non-empty time delay", - ValidationError.WORKFLOW_VALIDATION); - } - } - - if (s instanceof ParallelState) { - ParallelState parallelState = (ParallelState) s; - - if (parallelState.getBranches() == null - || parallelState.getBranches().size() < 2) { - addValidationError( - "Parallel state should have at lest two branches", - ValidationError.WORKFLOW_VALIDATION); - } - } - - if (s instanceof InjectState) { - InjectState injectState = (InjectState) s; - if (injectState.getData() == null || injectState.getData().isEmpty()) { - addValidationError( - "InjectState should have non-null data", - ValidationError.WORKFLOW_VALIDATION); - } - } - - if (s instanceof ForEachState) { - ForEachState forEachState = (ForEachState) s; - checkActionsDefinition(forEachState.getActions(), functions, events); - if (forEachState.getInputCollection() == null - || forEachState.getInputCollection().isEmpty()) { - addValidationError( - "ForEach state should have a valid inputCollection", - ValidationError.WORKFLOW_VALIDATION); - } - } - - if (s instanceof CallbackState) { - CallbackState callbackState = (CallbackState) s; - - if (isMissingEventsDefinition(callbackState.getEventRef(), events)) { - addValidationError( - "CallbackState event ref does not reference a defined workflow event definition", - ValidationError.WORKFLOW_VALIDATION); - } - - if (isMissingFunctionDefinition( - callbackState.getAction().getFunctionRef().getRefName(), functions)) { - addValidationError( - "CallbackState action function ref does not reference a defined workflow function definition", - ValidationError.WORKFLOW_VALIDATION); - } - } - }); - - if (validation.endStates == 0) { - addValidationError("No end state found.", ValidationError.WORKFLOW_VALIDATION); - } - } - - return validationErrors; - } - - @Override - public boolean isValid() { - return validate().isEmpty(); - } - - @Override - public WorkflowValidator setSchemaValidationEnabled(boolean schemaValidationEnabled) { - this.schemaValidationEnabled = schemaValidationEnabled; - return this; - } - - @Override - public WorkflowValidator reset() { - workflow = null; - validationErrors.clear(); - schemaValidationEnabled = true; - return this; - } - - private void checkActionsDefinition( - List actions, List functions, List events) { - if (actions == null) { - return; - } - for (Action action : actions) { - if (action.getFunctionRef() != null) { - if (action.getFunctionRef().getRefName().isEmpty()) { - addValidationError( - String.format( - "State action '%s' functionRef should not be null or empty", action.getName()), - ValidationError.WORKFLOW_VALIDATION); - } - - if (isMissingFunctionDefinition(action.getFunctionRef().getRefName(), functions)) { - addValidationError( - String.format( - "State action '%s' functionRef does not reference an existing workflow function definition", - action.getName()), - ValidationError.WORKFLOW_VALIDATION); - } - } - - if (action.getEventRef() != null) { - - if (isMissingEventsDefinition(action.getEventRef().getTriggerEventRef(), events)) { - addValidationError( - String.format( - "State action '%s' trigger event def does not reference an existing workflow event definition", - action.getName()), - ValidationError.WORKFLOW_VALIDATION); - } - - if (isMissingEventsDefinition(action.getEventRef().getResultEventRef(), events)) { - addValidationError( - String.format( - "State action '%s' results event def does not reference an existing workflow event definition", - action.getName()), - ValidationError.WORKFLOW_VALIDATION); - } - } - - if (action.getRetryRef() != null - && isMissingRetryDefinition(action.getRetryRef(), workflow.getRetries().getRetryDefs())) { - addValidationError( - String.format( - "Operation State action '%s' retryRef does not reference an existing workflow retry definition", - action.getName()), - ValidationError.WORKFLOW_VALIDATION); - } - } - } - - private boolean isMissingFunctionDefinition( - String functionName, List functions) { - if (functions != null) { - return !functions.stream().anyMatch(f -> f.getName().equals(functionName)); - } else { - return true; - } - } - - private boolean isMissingEventsDefinition(String eventName, List events) { - if (eventName == null) { - return false; - } - if (events != null) { - return !events.stream().anyMatch(e -> e.getName().equals(eventName)); - } else { - return true; - } - } - - private boolean isMissingRetryDefinition(String retryName, List retries) { - return retries == null - || !retries.stream().anyMatch(f -> f.getName() != null && f.getName().equals(retryName)); - } - - private static final Set skipMessages = - Set.of( - "$.start: string found, object expected", - "$.functions: array found, object expected", - "$.retries: array found, object expected", - "$.errors: array found, object expected", - "$.auth: array found, object expected"); - - private void addValidationError(String message, String type) { - if (skipMessages.contains(message)) { - return; - } - ValidationError mainError = new ValidationError(); - mainError.setMessage(message); - mainError.setType(type); - validationErrors.add(mainError); - } - - private class Validation { - final Set states = new HashSet<>(); - Integer endStates = 0; - - void addState(String name) { - if (states.contains(name)) { - addValidationError( - "State does not have an unique name: " + name, ValidationError.WORKFLOW_VALIDATION); - } else { - states.add(name); - } - } - - void addEndState() { - endStates++; - } - } -} diff --git a/validation/src/main/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowValidator b/validation/src/main/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowValidator deleted file mode 100644 index cebff91f..00000000 --- a/validation/src/main/resources/META-INF/services/io.serverlessworkflow.api.interfaces.WorkflowValidator +++ /dev/null @@ -1 +0,0 @@ -io.serverlessworkflow.validation.WorkflowValidatorImpl \ No newline at end of file diff --git a/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java b/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java deleted file mode 100644 index d8828b48..00000000 --- a/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright 2020-Present The Serverless Workflow Specification Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.serverlessworkflow.validation.test; - -import static io.serverlessworkflow.api.states.DefaultState.Type.OPERATION; -import static io.serverlessworkflow.api.states.DefaultState.Type.SLEEP; - -import com.fasterxml.jackson.databind.ObjectMapper; -import io.serverlessworkflow.api.Workflow; -import io.serverlessworkflow.api.actions.Action; -import io.serverlessworkflow.api.end.End; -import io.serverlessworkflow.api.error.ErrorDefinition; -import io.serverlessworkflow.api.events.EventDefinition; -import io.serverlessworkflow.api.events.EventRef; -import io.serverlessworkflow.api.functions.FunctionDefinition; -import io.serverlessworkflow.api.functions.FunctionDefinition.Type; -import io.serverlessworkflow.api.functions.FunctionRef; -import io.serverlessworkflow.api.interfaces.WorkflowValidator; -import io.serverlessworkflow.api.retry.RetryDefinition; -import io.serverlessworkflow.api.start.Start; -import io.serverlessworkflow.api.states.ForEachState; -import io.serverlessworkflow.api.states.InjectState; -import io.serverlessworkflow.api.states.OperationState; -import io.serverlessworkflow.api.states.SleepState; -import io.serverlessworkflow.api.validation.ValidationError; -import io.serverlessworkflow.api.workflow.Errors; -import io.serverlessworkflow.api.workflow.Events; -import io.serverlessworkflow.api.workflow.Functions; -import io.serverlessworkflow.api.workflow.Retries; -import io.serverlessworkflow.validation.WorkflowValidatorImpl; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class WorkflowValidationTest { - - @Test - public void testIncompleteJsonWithSchemaValidation() { - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = - workflowValidator.setSource("{\n" + " \"id\": \"abc\" \n" + "}").validate(); - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals(3, validationErrors.size()); - } - - @Test - public void testIncompleteYamlWithSchemaValidation() { - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = - workflowValidator.setSource("---\n" + "key: abc\n").validate(); - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals(4, validationErrors.size()); - } - - @Test - public void testFromIncompleteWorkflow() { - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withVersion("1.0") - .withStart(new Start()) - .withStates( - Arrays.asList( - new SleepState() - .withName("sleepState") - .withType(SLEEP) - .withEnd(new End()) - .withDuration("PT1M"))); - - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = workflowValidator.setWorkflow(workflow).validate(); - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals(1, validationErrors.size()); - Assertions.assertEquals( - "No state name found that matches the workflow start definition", - validationErrors.get(0).getMessage()); - } - - @Test - public void testWorkflowMissingStates() { - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = - workflowValidator - .setSource( - "{\n" - + "\t\"id\": \"testwf\",\n" - + "\t\"name\": \"test workflow\",\n" - + " \"version\": \"1.0\",\n" - + " \"start\": \"SomeState\",\n" - + " \"states\": []\n" - + "}") - .validate(); - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals(1, validationErrors.size()); - - Assertions.assertEquals("No states found", validationErrors.get(0).getMessage()); - } - - @Test - public void testWorkflowMissingStatesIdAndKey() { - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = - workflowValidator - .setSource( - "{\n" - + "\t\"name\": \"test workflow\",\n" - + " \"version\": \"1.0\",\n" - + " \"start\": \"SomeState\",\n" - + " \"states\": []\n" - + "}") - .validate(); - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals(1, validationErrors.size()); - - Assertions.assertEquals( - "$: required property 'id' not found", validationErrors.get(0).getMessage()); - } - - @Test - public void testOperationStateNoFunctionRef() { - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = - workflowValidator - .setSource( - "{\n" - + "\"id\": \"checkInbox\",\n" - + "\"name\": \"Check Inbox Workflow\",\n" - + "\"description\": \"Periodically Check Inbox\",\n" - + "\"version\": \"1.0\",\n" - + "\"start\": \"CheckInbox\",\n" - + "\"functions\": [\n" - + "\n" - + "],\n" - + "\"states\": [\n" - + " {\n" - + " \"name\": \"CheckInbox\",\n" - + " \"type\": \"operation\",\n" - + " \"actionMode\": \"sequential\",\n" - + " \"actions\": [\n" - + " {\n" - + " \"functionRef\": {\n" - + " \"refName\": \"checkInboxFunction\"\n" - + " }\n" - + " }\n" - + " ],\n" - + " \"transition\": {\n" - + " \"nextState\": \"SendTextForHighPrioriry\"\n" - + " }\n" - + " },\n" - + " {\n" - + " \"name\": \"SendTextForHighPrioriry\",\n" - + " \"type\": \"foreach\",\n" - + " \"inputCollection\": \"${ .message }\",\n" - + " \"iterationParam\": \"${ .singlemessage }\",\n" - + " \"end\": {\n" - + " \"kind\": \"default\"\n" - + " }\n" - + " }\n" - + "]\n" - + "}") - .validate(); - - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals(1, validationErrors.size()); - - Assertions.assertEquals( - "State action 'null' functionRef does not reference an existing workflow function definition", - validationErrors.get(0).getMessage()); - } - - @Test - public void testValidateWorkflowForOptionalStartStateAndWorkflowName() { - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withVersion("1.0") - .withStates( - Arrays.asList( - new SleepState() - .withName("sleepState") - .withType(SLEEP) - .withEnd(new End()) - .withDuration("PT1M"))); - - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = workflowValidator.setWorkflow(workflow).validate(); - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals(0, validationErrors.size()); - } - - @Test - public void testValidateWorkflowForOptionalIterationParam() { - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = - workflowValidator - .setSource( - "{\n" - + "\"id\": \"checkInbox\",\n" - + " \"name\": \"Check Inbox Workflow\",\n" - + "\"description\": \"Periodically Check Inbox\",\n" - + "\"version\": \"1.0\",\n" - + "\"start\": \"CheckInbox\",\n" - + "\"functions\": [\n" - + "\n" - + "],\n" - + "\"states\": [\n" - + " {\n" - + " \"name\": \"CheckInbox\",\n" - + " \"type\": \"operation\",\n" - + " \"actionMode\": \"sequential\",\n" - + " \"actions\": [\n" - + " {\n" - + " \"functionRef\": {\n" - + " \"refName\": \"checkInboxFunction\"\n" - + " }\n" - + " }\n" - + " ],\n" - + " \"transition\": {\n" - + " \"nextState\": \"SendTextForHighPrioriry\"\n" - + " }\n" - + " },\n" - + " {\n" - + " \"name\": \"SendTextForHighPrioriry\",\n" - + " \"type\": \"foreach\",\n" - + " \"inputCollection\": \"${ .message }\",\n" - + " \"end\": {\n" - + " \"kind\": \"default\"\n" - + " }\n" - + " }\n" - + "]\n" - + "}") - .validate(); - - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals( - 1, - validationErrors.size()); // validation error raised for functionref not for iterationParam - } - - @Test - public void testMissingFunctionRefForCallbackState() { - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = - workflowValidator - .setSource( - "{\n" - + " \"id\": \"callbackstatemissingfuncref\",\n" - + " \"version\": \"1.0\",\n" - + " \"specVersion\": \"0.8\",\n" - + " \"name\": \"Callback State Test\",\n" - + " \"start\": \"CheckCredit\",\n" - + " \"states\": [\n" - + " {\n" - + " \"name\": \"CheckCredit\",\n" - + " \"type\": \"callback\",\n" - + " \"action\": {\n" - + " \"functionRef\": {\n" - + " \"refName\": \"callCreditCheckMicroservice\",\n" - + " \"arguments\": {\n" - + " \"customer\": \"${ .customer }\"\n" - + " }\n" - + " }\n" - + " },\n" - + " \"eventRef\": \"CreditCheckCompletedEvent\",\n" - + " \"timeouts\": {\n" - + " \"stateExecTimeout\": \"PT15M\"\n" - + " },\n" - + " \"end\": true\n" - + " }\n" - + " ]\n" - + "}") - .validate(); - - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals(2, validationErrors.size()); - Assertions.assertEquals( - "CallbackState event ref does not reference a defined workflow event definition", - validationErrors.get(0).getMessage()); - Assertions.assertEquals( - "CallbackState action function ref does not reference a defined workflow function definition", - validationErrors.get(1).getMessage()); - } - - @Test - void testFunctionCall() { - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withVersion("1.0") - .withStart(new Start().withStateName("start")) - .withFunctions( - new Functions( - Arrays.asList(new FunctionDefinition("expression").withType(Type.EXPRESSION)))) - .withStates( - Arrays.asList( - new OperationState() - .withName("start") - .withType(OPERATION) - .withActions( - Arrays.asList( - new Action().withFunctionRef(new FunctionRef("expression")))) - .withEnd(new End()))); - Assertions.assertTrue(new WorkflowValidatorImpl().setWorkflow(workflow).validate().isEmpty()); - } - - @Test - void testEventCall() { - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withVersion("1.0") - .withStart(new Start().withStateName("start")) - .withEvents(new Events(Arrays.asList(new EventDefinition().withName("event")))) - .withRetries(new Retries(Arrays.asList(new RetryDefinition("start", "PT1S")))) - .withStates( - Arrays.asList( - new OperationState() - .withName("start") - .withType(OPERATION) - .withActions( - Arrays.asList( - new Action() - .withEventRef(new EventRef().withTriggerEventRef("event")))) - .withEnd(new End()))); - Assertions.assertTrue(new WorkflowValidatorImpl().setWorkflow(workflow).validate().isEmpty()); - } - - /** - * @see Validation missing out - * on refname in foreach>actions - */ - @Test - void testActionDefForEach() { - Workflow workflow = - new Workflow() - .withId("test-workflow") - .withVersion("1.0") - .withStart(new Start().withStateName("TestingForEach")) - .withFunctions(new Functions(Arrays.asList(new FunctionDefinition("Test")))) - .withStates( - Arrays.asList( - new ForEachState() - .withName("TestingForEach") - .withInputCollection("${ .archives }") - .withIterationParam("archive") - .withOutputCollection("${ .output}") - .withActions( - Arrays.asList( - new Action() - .withName("callFn") - .withFunctionRef(new FunctionRef("DoesNotExist")))) - .withEnd(new End()))); - final List validationErrors = - new WorkflowValidatorImpl().setWorkflow(workflow).validate(); - Assertions.assertEquals(1, validationErrors.size()); - Assertions.assertEquals( - "State action 'callFn' functionRef does not reference an existing workflow function definition", - validationErrors.get(0).getMessage()); - } - - /** - * @see Retry definition - * validation doesn't work - */ - @Test - public void testValidateRetry() { - WorkflowValidator workflowValidator = new WorkflowValidatorImpl(); - List validationErrors = - workflowValidator - .setSource( - "{\n" - + " \"id\": \"workflow_1\",\n" - + " \"name\": \"workflow_1\",\n" - + " \"description\": \"workflow_1\",\n" - + " \"version\": \"1.0\",\n" - + " \"specVersion\": \"0.8\",\n" - + " \"start\": \"Task1\",\n" - + " \"functions\": [\n" - + " {\n" - + " \"name\": \"increment\",\n" - + " \"type\": \"custom\",\n" - + " \"operation\": \"worker\"\n" - + " }\n" - + " ],\n" - + " \"retries\": [\n" - + " {\n" - + " \"maxAttempts\": 3\n" - + " },\n" - + " {\n" - + " \"name\": \"testRetry\" \n" - + " }\n" - + " ],\n" - + " \"states\": [\n" - + " {\n" - + " \"name\": \"Task1\",\n" - + " \"type\": \"operation\",\n" - + " \"actionMode\": \"sequential\",\n" - + " \"actions\": [\n" - + " {\n" - + " \"functionRef\": {\n" - + " \"refName\": \"increment\",\n" - + " \"arguments\": {\n" - + " \"input\": \"some text\"\n" - + " }\n" - + " },\n" - + " \"retryRef\": \"const\",\n" - + " \"actionDataFilter\": {\n" - + " \"toStateData\": \"${ .result }\"\n" - + " }\n" - + " }\n" - + " ],\n" - + " \"end\": true\n" - + " }\n" - + " ]\n" - + "}") - .validate(); - - Assertions.assertNotNull(validationErrors); - Assertions.assertEquals(2, validationErrors.size()); - Assertions.assertEquals("Retry name should not be empty", validationErrors.get(0).getMessage()); - Assertions.assertEquals( - "Operation State action 'null' retryRef does not reference an existing workflow retry definition", - validationErrors.get(1).getMessage()); - } - - /** - * @see WorkflowValidator - * validate Wrokflow.tojson(workflow) failed - */ - @Test - void testErrorsArrayParsing() { - final Workflow workflow = - new Workflow() - .withId("test-workflow") - .withName("test-workflow") - .withVersion("1.0") - .withStart(new Start().withStateName("testingErrors")) - .withErrors(new Errors(Arrays.asList(new ErrorDefinition()))) - .withStates( - Arrays.asList( - new InjectState() - .withName("testingErrors") - .withData(new ObjectMapper().createObjectNode().put("name", "Skywalker")) - .withEnd(new End()))); - Assertions.assertTrue( - new WorkflowValidatorImpl().setSource(Workflow.toJson(workflow)).isValid()); - } - - /** - * @see Error parsing Oauth - * properties in cncf spec using java sdk - */ - @Test - void testOAuthPropertiesDefinition() { - final Workflow workflow = - Workflow.fromSource( - "{\n" - + " \"version\": \"1.0.0\",\n" - + " \"id\": \"greeting-workflow\", \n" - + " \"specVersion\": \"0.8\",\n" - + " \"name\": \"greeting-workflow\",\n" - + " \"description\": \"Greet Someone\",\n" - + " \"start\": \"greet\",\n" - + " \"auth\": [\n" - + " {\n" - + " \"name\": \"serviceCloud\",\n" - + " \"scheme\": \"oauth2\",\n" - + " \"properties\": {\n" - + " \"scopes\": [\"$$$$XXXMMMMM\"],\n" - + " \"audiences\": [\"%%%XXXXXXX\"],\n" - + " \"clientId\": \"whatever\",\n" - + " \"grantType\": \"password\"\n" - + " }\n" - + " }\n" - + " ],\n" - + " \"functions\": [\n" - + " {\n" - + " \"name\": \"greeting-function\",\n" - + " \"type\": \"rest\",\n" - + " \"operation\": \"file://myapis/greetingapis.json#greeting\"\n" - + " }\n" - + " ],\n" - + " \"states\": [\n" - + " {\n" - + " \"name\": \"greet\",\n" - + " \"type\": \"operation\",\n" - + " \"actions\": [\n" - + " {\n" - + " \"name\": \"greet-action\",\n" - + " \"functionRef\": {\n" - + " \"refName\": \"greeting-function\",\n" - + " \"arguments\": {\n" - + " \"name\": \"${ .person.name }\"\n" - + " }\n" - + " },\n" - + " \"actionDataFilter\": {\n" - + " \"results\": \"${ {greeting: .greeting} }\"\n" - + " }\n" - + " }\n" - + " ],\n" - + " \"end\": true\n" - + " }\n" - + " ]\n" - + "}\n"); - final List validationErrors = - new WorkflowValidatorImpl().setWorkflow(workflow).validate(); - - Assertions.assertTrue(validationErrors.isEmpty()); - } -} From 074f5599e66cb0f44d613a76d33096754bfa5215 Mon Sep 17 00:00:00 2001 From: Francisco Javier Tirado Sarti Date: Mon, 17 Jun 2024 12:18:29 +0200 Subject: [PATCH 3/9] [Fix_#359] Handling anyOf Signed-off-by: Francisco Javier Tirado Sarti --- api/src/main/resources/schema/workflow.yaml | 265 +++++++++++------- .../generator/AllAnyOneOfSchemaRule.java | 165 +++++++++++ .../generator/UnreferencedFactory.java | 48 +--- 3 files changed, 322 insertions(+), 156 deletions(-) create mode 100644 custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java diff --git a/api/src/main/resources/schema/workflow.yaml b/api/src/main/resources/schema/workflow.yaml index f03ebe18..88435011 100644 --- a/api/src/main/resources/schema/workflow.yaml +++ b/api/src/main/resources/schema/workflow.yaml @@ -1,5 +1,5 @@ -$id: https://serverlessworkflow.io/schemas/1.0.0-alpha1/workflow.json -$schema: http://json-schema.org/draft-07/schema +$id: https://serverlessworkflow.io/schemas/1.0.0-alpha1/workflow.yaml +$schema: https://json-schema.org/draft/2020-12/schema description: Serverless Workflow DSL - Workflow Schema type: object properties: @@ -76,8 +76,8 @@ properties: description: The workflow's secrets. description: Defines the workflow's reusable components. do: - description: Defines the task the workflow must perform - $ref: '#/$defs/task' + description: Defines the task(s) the workflow must perform + $ref: '#/$defs/taskList' timeout: $ref: '#/$defs/timeout' description: The workflow's timeout configuration, if any. @@ -101,9 +101,20 @@ properties: description: Specifies the events that trigger the workflow execution. description: Schedules the workflow $defs: - task: + taskList: + type: array + items: + type: object + minProperties: 1 + maxProperties: 1 + additionalProperties: + $ref: '#/$defs/task' + taskBase: type: object properties: + if: + type: string + description: A runtime expression, if any, used to determine whether or not the task should be run. input: $ref: '#/$defs/input' description: Configure the task's input. @@ -119,9 +130,12 @@ $defs: then: $ref: '#/$defs/flowDirective' description: The flow directive to be performed upon completion of the task. + task: + unevaluatedProperties: false oneOf: - $ref: '#/$defs/callTask' - - $ref: '#/$defs/compositeTask' + - $ref: '#/$defs/doTask' + - $ref: '#/$defs/forkTask' - $ref: '#/$defs/emitTask' - $ref: '#/$defs/forTask' - $ref: '#/$defs/listenTask' @@ -132,9 +146,13 @@ $defs: - $ref: '#/$defs/tryTask' - $ref: '#/$defs/waitTask' callTask: - type: object oneOf: - - properties: + - title: CallAsyncAPI + $ref: '#/$defs/taskBase' + type: object + required: [ call, with ] + unevaluatedProperties: false + properties: call: type: string const: asyncapi @@ -165,9 +183,14 @@ $defs: - $ref: '#/$defs/authenticationPolicy' - type: string required: [ document, operationRef ] + additionalProperties: false description: Defines the AsyncAPI call to perform. + - title: CallGRPC + $ref: '#/$defs/taskBase' + type: object + unevaluatedProperties: false required: [ call, with ] - - properties: + properties: call: type: string const: grpc @@ -206,9 +229,14 @@ $defs: additionalProperties: true description: The arguments, if any, to call the method with. required: [ proto, service, method ] + additionalProperties: false description: Defines the GRPC call to perform. + - title: CallHTTP + $ref: '#/$defs/taskBase' + type: object + unevaluatedProperties: false required: [ call, with ] - - properties: + properties: call: type: string const: http @@ -234,9 +262,14 @@ $defs: enum: [ raw, content, response ] description: The http call output format. Defaults to 'content'. required: [ method, endpoint ] + additionalProperties: false description: Defines the HTTP call to perform. + - title: CallOpenAPI + $ref: '#/$defs/taskBase' + type: object + unevaluatedProperties: false required: [ call, with ] - - properties: + properties: call: type: string const: openapi @@ -263,9 +296,14 @@ $defs: enum: [ raw, content, response ] description: The http call output format. Defaults to 'content'. required: [ document, operationId ] + additionalProperties: false description: Defines the OpenAPI call to perform. - required: [ call, with ] - - properties: + - title: CallFunction + $ref: '#/$defs/taskBase' + type: object + unevaluatedProperties: false + required: [ call ] + properties: call: type: string not: @@ -275,46 +313,38 @@ $defs: type: object additionalProperties: true description: A name/value mapping of the parameters, if any, to call the function with. - required: [ call ] - compositeTask: - type: object - required: [ execute ] - description: Serves as a pivotal orchestrator within workflow systems, enabling the seamless integration and execution of multiple subtasks to accomplish complex operations + forkTask: + description: Allows workflows to execute multiple tasks concurrently and optionally race them against each other, with a single possible winner, which sets the task's output. + $ref: '#/$defs/taskBase' + type: object + unevaluatedProperties: false + required: [ fork ] properties: - execute: + fork: type: object - description: Configures the task execution strategy to use - oneOf: - - required: [ concurrently ] - properties: - concurrently: - description: A list of the tasks to perform concurrently. - type: array - minItems: 2 - items: - type: object - minProperties: 1 - maxProperties: 1 - additionalProperties: - $ref: '#/$defs/task' - compete: - description: Indicates whether or not the concurrent tasks are racing against each other, with a single possible winner, which sets the composite task's output. - type: boolean - default: false - - required: [ sequentially ] - properties: - sequentially: - description: A list of the tasks to perform sequentially. - type: array - minItems: 2 - items: - type: object - minProperties: 1 - maxProperties: 1 - additionalProperties: - $ref: '#/$defs/task' + required: [ branches ] + properties: + branches: + $ref: '#/$defs/taskList' + compete: + description: Indicates whether or not the concurrent tasks are racing against each other, with a single possible winner, which sets the composite task's output. + type: boolean + default: false + doTask: + description: Allows to execute a list of tasks in sequence + $ref: '#/$defs/taskBase' + type: object + unevaluatedProperties: false + required: [ do ] + properties: + do: + $ref: '#/$defs/taskList' emitTask: + description: Allows workflows to publish events to event brokers or messaging systems, facilitating communication and coordination between different components and services. + $ref: '#/$defs/taskBase' type: object + required: [ emit ] + unevaluatedProperties: false properties: emit: type: object @@ -346,17 +376,12 @@ $defs: required: [ source, type ] additionalProperties: true required: [ event ] - required: [ emit ] - description: Allows workflows to publish events to event brokers or messaging systems, facilitating communication and coordination between different components and services. - flowDirective: - additionalProperties: false - anyOf: - - type: string - enum: [ continue, exit, end ] - default: continue - - type: string forTask: + description: Allows workflows to iterate over a collection of items, executing a defined set of subtasks for each item in the collection. This task type is instrumental in handling scenarios such as batch processing, data transformation, and repetitive operations across datasets. + $ref: '#/$defs/taskBase' type: object + required: [ for, do ] + unevaluatedProperties: false properties: for: type: object @@ -377,11 +402,13 @@ $defs: type: string description: A runtime expression that represents the condition, if any, that must be met for the iteration to continue. do: - $ref: '#/$defs/task' - description: Allows workflows to iterate over a collection of items, executing a defined set of subtasks for each item in the collection. This task type is instrumental in handling scenarios such as batch processing, data transformation, and repetitive operations across datasets. - required: [ for, do ] + $ref: '#/$defs/taskList' listenTask: + description: Provides a mechanism for workflows to await and react to external events, enabling event-driven behavior within workflow systems. + $ref: '#/$defs/taskBase' type: object + required: [ listen ] + unevaluatedProperties: false properties: listen: type: object @@ -390,10 +417,12 @@ $defs: $ref: '#/$defs/eventConsumptionStrategy' description: Defines the event(s) to listen to. required: [ to ] - required: [ listen ] - description: Provides a mechanism for workflows to await and react to external events, enabling event-driven behavior within workflow systems. raiseTask: + description: Intentionally triggers and propagates errors. + $ref: '#/$defs/taskBase' type: object + required: [ raise ] + unevaluatedProperties: false properties: raise: type: object @@ -402,10 +431,12 @@ $defs: $ref: '#/$defs/error' description: Defines the error to raise. required: [ error ] - required: [ raise ] - description: Intentionally triggers and propagates errors. runTask: + description: Provides the capability to execute external containers, shell commands, scripts, or workflows. + $ref: '#/$defs/taskBase' type: object + required: [ run ] + unevaluatedProperties: false properties: run: type: object @@ -444,16 +475,16 @@ $defs: additionalProperties: true description: A key/value mapping of the environment variables, if any, to use when running the configured process. oneOf: - - properties: - code: - type: string - required: [ code ] - description: The script's code. - - properties: - source: - $ref: '#/$defs/externalResource' - description: The script's resource. - required: [ code ] + - properties: + code: + type: string + required: [ code ] + description: The script's code. + - properties: + source: + $ref: '#/$defs/externalResource' + description: The script's resource. + required: [ source ] required: [ language ] required: [ script ] description: Enables the execution of custom scripts or code within a workflow, empowering workflows to perform specialized logic, data processing, or integration tasks by executing user-defined scripts written in various programming languages. @@ -496,20 +527,24 @@ $defs: required: [ namespace, name, version ] required: [ workflow ] description: Enables the invocation and execution of nested workflows within a parent workflow, facilitating modularization, reusability, and abstraction of complex logic or business processes by encapsulating them into standalone workflow units. - required: [ run ] - description: Provides the capability to execute external containers, shell commands, scripts, or workflows. setTask: + description: A task used to set data + $ref: '#/$defs/taskBase' type: object + required: [ set ] + unevaluatedProperties: false properties: set: type: object minProperties: 1 additionalProperties: true description: The data to set - required: [ set ] - description: A task used to set data switchTask: + description: Enables conditional branching within workflows, allowing them to dynamically select different paths based on specified conditions or criteria + $ref: '#/$defs/taskBase' type: object + required: [ switch ] + unevaluatedProperties: false properties: switch: type: array @@ -530,14 +565,16 @@ $defs: then: $ref: '#/$defs/flowDirective' description: The flow directive to execute when the case matches. - required: [ switch ] - description: Enables conditional branching within workflows, allowing them to dynamically select different paths based on specified conditions or criteria tryTask: + description: Serves as a mechanism within workflows to handle errors gracefully, potentially retrying failed tasks before proceeding with alternate ones. + $ref: '#/$defs/taskBase' type: object + required: [ try, catch ] + unevaluatedProperties: false properties: try: - description: The task to perform. - $ref: '#/$defs/task' + description: The task(s) to perform. + $ref: '#/$defs/taskList' catch: type: object properties: @@ -556,18 +593,25 @@ $defs: $ref: '#/$defs/retryPolicy' description: The retry policy to use, if any, when catching errors. do: - description: The definition of the task to run when catching an error. - $ref: '#/$defs/task' - required: [ try, catch ] - description: Serves as a mechanism within workflows to handle errors gracefully, potentially retrying failed tasks before proceeding with alternate ones. + description: The definition of the task(s) to run when catching an error. + $ref: '#/$defs/taskList' waitTask: + description: Allows workflows to pause or delay their execution for a specified period of time. + $ref: '#/$defs/taskBase' type: object + required: [ wait ] + unevaluatedProperties: false properties: wait: - $ref: '#/$defs/duration' description: The amount of time to wait. - required: [ wait ] - description: Allows workflows to pause or delay their execution for a specified period of time. + $ref: '#/$defs/duration' + flowDirective: + additionalProperties: false + anyOf: + - type: string + enum: [ continue, exit, end ] + default: continue + - type: string authenticationPolicy: type: object oneOf: @@ -683,7 +727,7 @@ $defs: description: The status code generated by the origin for this occurrence of the error. instance: type: string - format: uri + format: json-pointer description: A JSON Pointer used to reference the component the error originates from. title: type: string @@ -780,29 +824,32 @@ $defs: type: string description: A runtime expression, if any, used to determine whether or not the extension should apply in the specified context. before: - description: The task to execute before the extended task, if any. - $ref: '#/$defs/task' + description: The task(s) to execute before the extended task, if any. + $ref: '#/$defs/taskList' after: - description: The task to execute after the extended task, if any. - $ref: '#/$defs/task' + description: The task(s) to execute after the extended task, if any. + $ref: '#/$defs/taskList' required: [ extend ] description: The definition of a an extension. externalResource: - type: object - properties: - uri: - type: string + oneOf: + - type: string format: uri - description: The endpoint's URI. - authentication: - description: The authentication policy to use. - oneOf: - - $ref: '#/$defs/authenticationPolicy' - - type: string - name: - type: string - description: The external resource's name, if any. - required: [ uri ] + - type: object + properties: + uri: + type: string + format: uri + description: The endpoint's URI. + authentication: + description: The authentication policy to use. + oneOf: + - $ref: '#/$defs/authenticationPolicy' + - type: string + name: + type: string + description: The external resource's name, if any. + required: [ uri ] input: type: object properties: diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java new file mode 100644 index 00000000..8358e193 --- /dev/null +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java @@ -0,0 +1,165 @@ +package io.serverlessworkflow.generator; + +import static org.apache.commons.lang3.StringUtils.*; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.sun.codemodel.JClass; +import com.sun.codemodel.JClassContainer; +import com.sun.codemodel.JDefinedClass; +import com.sun.codemodel.JType; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLDecoder; +import java.util.Optional; +import org.jsonschema2pojo.Jsonschema2Pojo; +import org.jsonschema2pojo.Schema; +import org.jsonschema2pojo.exception.GenerationException; +import org.jsonschema2pojo.rules.RuleFactory; +import org.jsonschema2pojo.rules.SchemaRule; + +public class AllAnyOneOfSchemaRule extends SchemaRule { + + private RuleFactory ruleFactory; + + protected AllAnyOneOfSchemaRule(RuleFactory ruleFactory) { + super(ruleFactory); + this.ruleFactory = ruleFactory; + } + + @Override + public JType apply( + String nodeName, + JsonNode schemaNode, + JsonNode parent, + JClassContainer generatableType, + Schema schema) { + + Optional refType = refType(nodeName, schemaNode, parent, generatableType, schema); + Optional oneOfType = oneOfType(nodeName, schemaNode, parent, generatableType, schema); + + Optional justOne = justOne(refType, oneOfType); + + if (!schemaNode.has("properties") && justOne.isPresent()) { + return justOne.get(); + } + + JType javaType = + schemaNode.has("enum") + ? ruleFactory.getEnumRule().apply(nodeName, schemaNode, parent, generatableType, schema) + : ruleFactory + .getTypeRule() + .apply(nodeName, schemaNode, parent, generatableType.getPackage(), schema); + + if (javaType instanceof JDefinedClass) { + JDefinedClass definedClass = (JDefinedClass) javaType; + if (justOne.filter(JClass.class::isInstance).isPresent()) { + definedClass._extends((JClass) justOne.get()); + } else { + wrapIt(definedClass, refType, oneOfType); + } + } + schema.setJavaTypeIfEmpty(javaType); + + return javaType; + } + + @SafeVarargs + private void wrapIt(JDefinedClass definedClass, Optional... optionals) { + for (Optional optional : optionals) { + optional.ifPresent(c -> wrapIt(definedClass, c)); + } + } + + private void wrapIt(JDefinedClass definedClass, JType type) { + // TODO include all paremeters of given type into the defined class + } + + @SafeVarargs + private Optional justOne(Optional... optionals) { + + Optional result = Optional.empty(); + for (Optional optional : optionals) { + if (optional.isPresent()) { + if (result.isPresent()) { + return Optional.empty(); + } else { + result = optional; + } + } + } + return result; + } + + private Optional oneOfType( + String nodeName, + JsonNode schemaNode, + JsonNode parent, + JClassContainer generatableType, + Schema parentSchema) { + if (schemaNode.has("oneOf")) { + int i = 0; + for (JsonNode oneOf : (ArrayNode) schemaNode.get("oneOf")) { + apply( + nodeName, + oneOf, + parent, + generatableType.getPackage(), + ruleFactory + .getSchemaStore() + .create( + URI.create(parentSchema.getId().toString() + "/oneOf/" + i++), + ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters())); + } + } + return Optional.empty(); + } + + private Optional refType( + String nodeName, + JsonNode schemaNode, + JsonNode parent, + JClassContainer generatableType, + Schema parentSchema) { + if (schemaNode.has("$ref")) { + String ref = schemaNode.get("$ref").asText(); + Schema schema = + ruleFactory + .getSchemaStore() + .create( + parentSchema, + ref, + ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters()); + + return Optional.of( + schema.isGenerated() + ? schema.getJavaType() + : apply( + nameFromRef(ref, nodeName), + schema.getContent(), + parent, + generatableType, + schema)); + } + return Optional.empty(); + } + + private String nameFromRef(String ref, String nodeName) { + if ("#".equals(ref)) { + return nodeName; + } + String nameFromRef; + if (!ref.contains("#")) { + nameFromRef = Jsonschema2Pojo.getNodeName(ref, ruleFactory.getGenerationConfig()); + } else { + String[] nameParts = split(ref, "/\\#"); + nameFromRef = nameParts[nameParts.length - 1]; + } + + try { + return URLDecoder.decode(nameFromRef, "utf-8"); + } catch (UnsupportedEncodingException e) { + throw new GenerationException("Failed to decode ref: " + ref, e); + } + } +} diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java index be36d3d5..3ea9a72f 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java @@ -1,59 +1,13 @@ package io.serverlessworkflow.generator; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.sun.codemodel.JClassContainer; import com.sun.codemodel.JType; -import java.util.Iterator; -import org.jsonschema2pojo.Schema; import org.jsonschema2pojo.rules.Rule; import org.jsonschema2pojo.rules.RuleFactory; -import org.jsonschema2pojo.rules.SchemaRule; public class UnreferencedFactory extends RuleFactory { @Override public Rule getSchemaRule() { - return new MySchemaRule(this); - } - - private class MySchemaRule extends SchemaRule { - - public MySchemaRule(UnreferencedFactory jsonSchemaRuleFactory) { - super(jsonSchemaRuleFactory); - } - - @Override - public JType apply( - String nodeName, - JsonNode schemaNode, - JsonNode parent, - JClassContainer generatableType, - Schema schema) { - JType result = super.apply(nodeName, schemaNode, parent, generatableType, schema); - final JsonNode definitions = schemaNode.get("$defs"); - if (definitions != null && definitions.isObject()) { - final ObjectNode objectNode = (ObjectNode) definitions; - final Iterator nodeIterator = objectNode.fieldNames(); - while (nodeIterator.hasNext()) { - final String name = nodeIterator.next(); - try { - getSchemaRule() - .apply( - name, - (ObjectNode) objectNode.get(name), - schemaNode, - generatableType.getPackage(), - getSchemaStore() - .create( - schema, - "#/$defs/" + name, - getGenerationConfig().getRefFragmentPathDelimiters())); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - } - return result; - } + return new AllAnyOneOfSchemaRule(this); } } From 84fff103ec23d2d0abd09e8ba5ed2d8ac117f609 Mon Sep 17 00:00:00 2001 From: Francisco Javier Tirado Sarti Date: Wed, 19 Jun 2024 11:33:27 +0200 Subject: [PATCH 4/9] [Fix_#359] Common class Signed-off-by: Francisco Javier Tirado Sarti --- .../generator/AllAnyOneOfSchemaRule.java | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java index 8358e193..a52dce63 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java @@ -11,7 +11,10 @@ import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; +import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Optional; +import java.util.Set; import org.jsonschema2pojo.Jsonschema2Pojo; import org.jsonschema2pojo.Schema; import org.jsonschema2pojo.exception.GenerationException; @@ -99,18 +102,40 @@ private Optional oneOfType( Schema parentSchema) { if (schemaNode.has("oneOf")) { int i = 0; + Set oneOfClasses = new HashSet<>(); for (JsonNode oneOf : (ArrayNode) schemaNode.get("oneOf")) { - apply( - nodeName, - oneOf, - parent, - generatableType.getPackage(), - ruleFactory - .getSchemaStore() - .create( - URI.create(parentSchema.getId().toString() + "/oneOf/" + i++), - ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters())); + oneOfClasses.add( + apply( + nodeName, + oneOf, + parent, + generatableType.getPackage(), + ruleFactory + .getSchemaStore() + .create( + URI.create(parentSchema.getId().toString() + "/oneOf/" + i++), + ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters()))); } + + Set commonAncestors = null; + for (JType oneOfClass : oneOfClasses) { + Set ancestors = new LinkedHashSet<>(); + while (oneOfClass instanceof JClass) { + JClass parentClass = ((JClass) oneOfClass)._extends(); + if (parentClass instanceof JClass && !parentClass.name().equals("Object")) { + ancestors.add(parentClass); + } + oneOfClass = parentClass; + } + if (commonAncestors == null) { + commonAncestors = ancestors; + } else { + commonAncestors.retainAll(ancestors); + } + } + return commonAncestors.isEmpty() + ? Optional.empty() + : Optional.of(commonAncestors.iterator().next()); } return Optional.empty(); } From e80e14996772cfe8ac130c6da4ff6623c3ab2f68 Mon Sep 17 00:00:00 2001 From: Francisco Javier Tirado Sarti Date: Wed, 19 Jun 2024 12:24:39 +0200 Subject: [PATCH 5/9] [Fix #359] Deserialization Signed-off-by: Francisco Javier Tirado Sarti --- api/src/test/resources/features/callHttp.yaml | 17 ++- .../test/resources/features/callOpenAPI.yaml | 20 ++-- .../test/resources/features/composite.yaml | 29 +++-- .../test/resources/features/data-flow.yaml | 26 ++--- api/src/test/resources/features/emit.yaml | 22 ++-- api/src/test/resources/features/flow.yaml | 24 ++-- api/src/test/resources/features/for.yaml | 21 ++-- api/src/test/resources/features/raise.yaml | 18 +-- api/src/test/resources/features/set.yaml | 16 +-- api/src/test/resources/features/switch.yaml | 52 ++++----- api/src/test/resources/features/try.yaml | 40 ++++--- .../generator/AllAnyOneOfSchemaRule.java | 109 +++++++----------- 12 files changed, 182 insertions(+), 212 deletions(-) diff --git a/api/src/test/resources/features/callHttp.yaml b/api/src/test/resources/features/callHttp.yaml index b7f8457d..9b48c783 100644 --- a/api/src/test/resources/features/callHttp.yaml +++ b/api/src/test/resources/features/callHttp.yaml @@ -1,13 +1,12 @@ document: dsl: 1.0.0-alpha1 namespace: default - name: http-call-with-content-output + name: http-call-with-response-output do: - getFirstAvailablePet: - call: http - with: - method: get - endpoint: - uri: https://petstore.swagger.io/v2/pet/findByStatus?status={status} - output: - from: .[0] + - getPet: + call: http + with: + method: get + endpoint: + uri: https://petstore.swagger.io/v2/pet/{petId} + output: response \ No newline at end of file diff --git a/api/src/test/resources/features/callOpenAPI.yaml b/api/src/test/resources/features/callOpenAPI.yaml index fef1ae95..b83b3f5e 100644 --- a/api/src/test/resources/features/callOpenAPI.yaml +++ b/api/src/test/resources/features/callOpenAPI.yaml @@ -3,13 +3,13 @@ document: namespace: default name: openapi-call-with-content-output do: - getPetsByStatus: - call: openapi - with: - document: - uri: https://petstore.swagger.io/v2/swagger.json - operation: findPetsByStatus - parameters: - status: ${ .status } - output: - from: . | length \ No newline at end of file + - findPet: + call: openapi + with: + document: + uri: "https://petstore.swagger.io/v2/swagger.json" + operation: findPetsByStatus + parameters: + status: ${ .status } + output: + from: . | length \ No newline at end of file diff --git a/api/src/test/resources/features/composite.yaml b/api/src/test/resources/features/composite.yaml index 28c448c2..7ea3b451 100644 --- a/api/src/test/resources/features/composite.yaml +++ b/api/src/test/resources/features/composite.yaml @@ -1,17 +1,16 @@ document: - dsl: 1.0.0-alpha1 - namespace: default - name: composite-sequential + dsl: 1.0.0-alpha1 + namespace: default + name: do do: - setRGB: - execute: - sequentially: - setRed: - set: - colors: ${ .colors + ["red"] } - setGreen: - set: - colors: ${ .colors + ["green"] } - setBlue: - set: - colors: ${ .colors + ["blue"] } + - compositeExample: + do: + - setRed: + set: + colors: ${ .colors + ["red"] } + - setGreen: + set: + colors: ${ .colors + ["green"] } + - setBlue: + set: + colors: ${ .colors + ["blue"] } \ No newline at end of file diff --git a/api/src/test/resources/features/data-flow.yaml b/api/src/test/resources/features/data-flow.yaml index d1d76418..d66d7848 100644 --- a/api/src/test/resources/features/data-flow.yaml +++ b/api/src/test/resources/features/data-flow.yaml @@ -1,21 +1,13 @@ document: dsl: 1.0.0-alpha1 namespace: default - name: non-object-output + name: output-filtering do: - getPetById1: - call: http - with: - method: get - endpoint: - uri: https://petstore.swagger.io/v2/pet/{petId} #simple interpolation, only possible with top level variables - output: - from: .id - getPetById2: - call: http - with: - method: get - endpoint: - uri: https://petstore.swagger.io/v2/pet/2 - output: - from: '{ ids: [ $input, .id ] }' + - getPet: + call: http + with: + method: get + endpoint: + uri: https://petstore.swagger.io/v2/pet/{petId} #simple interpolation, only possible with top level variables + output: + as: .id #filters the output of the http call, using only the id of the returned object diff --git a/api/src/test/resources/features/emit.yaml b/api/src/test/resources/features/emit.yaml index d9bfabcd..488feedc 100644 --- a/api/src/test/resources/features/emit.yaml +++ b/api/src/test/resources/features/emit.yaml @@ -1,13 +1,13 @@ document: - dsl: 1.0.0-alpha1 - namespace: default - name: emit + dsl: 1.0.0-alpha1 + namespace: default + name: emit do: - emitUserGreeted: - emit: - event: - with: - source: https://fake-source.com - type: com.fake-source.user.greeted.v1 - data: - greetings: ${ "Hello \(.user.firstName) \(.user.lastName)!" } + - emitEvent: + emit: + event: + with: + source: https://fake-source.com + type: com.fake-source.user.greeted.v1 + data: + greetings: ${ "Hello \(.user.firstName) \(.user.lastName)!" } \ No newline at end of file diff --git a/api/src/test/resources/features/flow.yaml b/api/src/test/resources/features/flow.yaml index 631b25ac..83baf04c 100644 --- a/api/src/test/resources/features/flow.yaml +++ b/api/src/test/resources/features/flow.yaml @@ -1,14 +1,14 @@ document: - dsl: 1.0.0-alpha1 - namespace: default - name: implicit-sequence + dsl: 1.0.0-alpha1 + namespace: default + name: implicit-sequence do: - setRed: - set: - colors: '${ .colors + [ "red" ] }' - setGreen: - set: - colors: '${ .colors + [ "green" ] }' - setBlue: - set: - colors: '${ .colors + [ "blue" ] }' + - setRed: + set: + colors: '${ .colors + [ "red" ] }' + - setGreen: + set: + colors: '${ .colors + [ "green" ] }' + - setBlue: + set: + colors: '${ .colors + [ "blue" ] }' diff --git a/api/src/test/resources/features/for.yaml b/api/src/test/resources/features/for.yaml index b7bc9b6f..f8ae826d 100644 --- a/api/src/test/resources/features/for.yaml +++ b/api/src/test/resources/features/for.yaml @@ -1,12 +1,13 @@ document: - dsl: 1.0.0-alpha1 - namespace: default - name: for + dsl: 1.0.0-alpha1 + namespace: default + name: for do: - forEachColor: - for: - each: color - in: '.colors' - do: - set: - processed: '${ { colors: (.processed.colors + [ $color ]), indexes: (.processed.indexes + [ $index ])} }' + - loopColors: + for: + each: color + in: '.colors' + do: + - markProcessed: + set: + processed: '${ { colors: (.processed.colors + [ $color ]), indexes: (.processed.indexes + [ $index ])} }' \ No newline at end of file diff --git a/api/src/test/resources/features/raise.yaml b/api/src/test/resources/features/raise.yaml index 48e3e572..9dd6b4f3 100644 --- a/api/src/test/resources/features/raise.yaml +++ b/api/src/test/resources/features/raise.yaml @@ -1,11 +1,11 @@ document: - dsl: 1.0.0-alpha1 - namespace: default - name: raise-custom-error + dsl: 1.0.0-alpha1 + namespace: default + name: raise-custom-error do: - raiseComplianceError: - raise: - error: - status: 400 - type: https://serverlessworkflow.io/errors/types/compliance - title: Compliance Error + - raiseError: + raise: + error: + status: 400 + type: https://serverlessworkflow.io/errors/types/compliance + title: Compliance Error \ No newline at end of file diff --git a/api/src/test/resources/features/set.yaml b/api/src/test/resources/features/set.yaml index 794176a3..1589792f 100644 --- a/api/src/test/resources/features/set.yaml +++ b/api/src/test/resources/features/set.yaml @@ -1,10 +1,10 @@ document: - dsl: 1.0.0-alpha1 - namespace: default - name: set + dsl: 1.0.0-alpha1 + namespace: default + name: set do: - initialize: - set: - shape: circle - size: ${ .configuration.size } - fill: ${ .configuration.fill } + - setShape: + set: + shape: circle + size: ${ .configuration.size } + fill: ${ .configuration.fill } diff --git a/api/src/test/resources/features/switch.yaml b/api/src/test/resources/features/switch.yaml index f299b5cc..74d046cb 100644 --- a/api/src/test/resources/features/switch.yaml +++ b/api/src/test/resources/features/switch.yaml @@ -1,28 +1,28 @@ document: - dsl: 1.0.0-alpha1 - namespace: default - name: switch-match + dsl: 1.0.0-alpha1 + namespace: default + name: switch-match do: - switchColor: - switch: - red: - when: '.color == "red"' - then: setRed - green: - when: '.color == "green"' - then: setGreen - blue: - when: '.color == "blue"' - then: setBlue - setRed: - set: - colors: '${ .colors + [ "red" ] }' - then: end - setGreen: - set: - colors: '${ .colors + [ "green" ] }' - then: end - setBlue: - set: - colors: '${ .colors + [ "blue" ] }' - then: end + - switchColor: + switch: + - red: + when: '.color == "red"' + then: setRed + - green: + when: '.color == "green"' + then: setGreen + - blue: + when: '.color == "blue"' + then: setBlue + - setRed: + set: + colors: '${ .colors + [ "red" ] }' + then: end + - setGreen: + set: + colors: '${ .colors + [ "green" ] }' + then: end + - setBlue: + set: + colors: '${ .colors + [ "blue" ] }' + then: end diff --git a/api/src/test/resources/features/try.yaml b/api/src/test/resources/features/try.yaml index 0f028588..7f9ba599 100644 --- a/api/src/test/resources/features/try.yaml +++ b/api/src/test/resources/features/try.yaml @@ -1,21 +1,23 @@ document: - dsl: 1.0.0-alpha1 - namespace: default - name: try-catch-404 + dsl: 1.0.0-alpha1 + namespace: default + name: try-catch-404 do: - tryGetPet: - try: - call: http - with: - method: get - endpoint: - uri: https://petstore.swagger.io/v2/pet/getPetByName/{petName} - catch: - errors: - with: - type: https://serverlessworkflow.io/dsl/errors/types/communication - status: 404 - as: err - do: - set: - error: ${ $err } + - tryGetPet: + try: + - getPet: + call: http + with: + method: get + endpoint: + uri: https://petstore.swagger.io/v2/pet/getPetByName/{petName} + catch: + errors: + with: + type: https://serverlessworkflow.io/dsl/errors/types/communication + status: 404 + as: err + do: + - setError: + set: + error: ${ $err } diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java index a52dce63..e3c80267 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java @@ -2,30 +2,33 @@ import static org.apache.commons.lang3.StringUtils.*; +import com.fasterxml.jackson.annotation.JsonUnwrapped; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.sun.codemodel.JClass; import com.sun.codemodel.JClassContainer; import com.sun.codemodel.JDefinedClass; +import com.sun.codemodel.JFieldVar; +import com.sun.codemodel.JMethod; +import com.sun.codemodel.JMod; import com.sun.codemodel.JType; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; +import java.util.Collection; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.Optional; -import java.util.Set; import org.jsonschema2pojo.Jsonschema2Pojo; import org.jsonschema2pojo.Schema; import org.jsonschema2pojo.exception.GenerationException; import org.jsonschema2pojo.rules.RuleFactory; import org.jsonschema2pojo.rules.SchemaRule; -public class AllAnyOneOfSchemaRule extends SchemaRule { +class AllAnyOneOfSchemaRule extends SchemaRule { private RuleFactory ruleFactory; - protected AllAnyOneOfSchemaRule(RuleFactory ruleFactory) { + AllAnyOneOfSchemaRule(RuleFactory ruleFactory) { super(ruleFactory); this.ruleFactory = ruleFactory; } @@ -39,12 +42,14 @@ public JType apply( Schema schema) { Optional refType = refType(nodeName, schemaNode, parent, generatableType, schema); - Optional oneOfType = oneOfType(nodeName, schemaNode, parent, generatableType, schema); + Collection unionTypes = new HashSet<>(); - Optional justOne = justOne(refType, oneOfType); + unionType("oneOf", nodeName, schemaNode, parent, generatableType, schema, unionTypes); + unionType("anyOf", nodeName, schemaNode, parent, generatableType, schema, unionTypes); + unionType("allOf", nodeName, schemaNode, parent, generatableType, schema, unionTypes); - if (!schemaNode.has("properties") && justOne.isPresent()) { - return justOne.get(); + if (!schemaNode.has("properties") && unionTypes.isEmpty() && refType.isPresent()) { + return refType.get(); } JType javaType = @@ -56,55 +61,48 @@ public JType apply( if (javaType instanceof JDefinedClass) { JDefinedClass definedClass = (JDefinedClass) javaType; - if (justOne.filter(JClass.class::isInstance).isPresent()) { - definedClass._extends((JClass) justOne.get()); - } else { - wrapIt(definedClass, refType, oneOfType); - } + refType.ifPresent( + type -> { + if (type instanceof JClass) { + definedClass._extends((JClass) type); + } else { + wrapIt(definedClass, type); + } + }); + unionTypes.forEach(unionType -> wrapIt(definedClass, unionType)); } schema.setJavaTypeIfEmpty(javaType); return javaType; } - @SafeVarargs - private void wrapIt(JDefinedClass definedClass, Optional... optionals) { - for (Optional optional : optionals) { - optional.ifPresent(c -> wrapIt(definedClass, c)); - } - } - - private void wrapIt(JDefinedClass definedClass, JType type) { - // TODO include all paremeters of given type into the defined class - } - - @SafeVarargs - private Optional justOne(Optional... optionals) { - - Optional result = Optional.empty(); - for (Optional optional : optionals) { - if (optional.isPresent()) { - if (result.isPresent()) { - return Optional.empty(); - } else { - result = optional; - } - } - } - return result; + private void wrapIt(JDefinedClass definedClass, JType unionType) { + JFieldVar instanceField = + definedClass.field( + JMod.PRIVATE, + unionType, + ruleFactory.getNameHelper().getPropertyName(unionType.name(), null)); + instanceField.annotate(JsonUnwrapped.class); + JMethod method = + definedClass.method( + JMod.PUBLIC, + unionType, + ruleFactory.getNameHelper().getGetterName(unionType.name(), unionType, null)); + method.body()._return(instanceField); } - private Optional oneOfType( + private void unionType( + String prefix, String nodeName, JsonNode schemaNode, JsonNode parent, JClassContainer generatableType, - Schema parentSchema) { - if (schemaNode.has("oneOf")) { + Schema parentSchema, + Collection types) { + if (schemaNode.has(prefix)) { int i = 0; - Set oneOfClasses = new HashSet<>(); - for (JsonNode oneOf : (ArrayNode) schemaNode.get("oneOf")) { - oneOfClasses.add( + for (JsonNode oneOf : (ArrayNode) schemaNode.get(prefix)) { + types.add( apply( nodeName, oneOf, @@ -113,31 +111,10 @@ private Optional oneOfType( ruleFactory .getSchemaStore() .create( - URI.create(parentSchema.getId().toString() + "/oneOf/" + i++), + URI.create(parentSchema.getId().toString() + '/' + prefix + '/' + i++), ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters()))); } - - Set commonAncestors = null; - for (JType oneOfClass : oneOfClasses) { - Set ancestors = new LinkedHashSet<>(); - while (oneOfClass instanceof JClass) { - JClass parentClass = ((JClass) oneOfClass)._extends(); - if (parentClass instanceof JClass && !parentClass.name().equals("Object")) { - ancestors.add(parentClass); - } - oneOfClass = parentClass; - } - if (commonAncestors == null) { - commonAncestors = ancestors; - } else { - commonAncestors.retainAll(ancestors); - } - } - return commonAncestors.isEmpty() - ? Optional.empty() - : Optional.of(commonAncestors.iterator().next()); } - return Optional.empty(); } private Optional refType( From a2f268bc128e7f0e3d68e7b8deaa23569a1d9cb5 Mon Sep 17 00:00:00 2001 From: Francisco Javier Tirado Sarti Date: Fri, 21 Jun 2024 12:53:03 +0200 Subject: [PATCH 6/9] [Fix #359] More deserialization Signed-off-by: Francisco Javier Tirado Sarti --- .../api/ObjectMapperFactory.java | 4 +- .../generator/AllAnyOneOfSchemaRule.java | 96 ++++++++++++------- 2 files changed, 66 insertions(+), 34 deletions(-) diff --git a/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java index 7bc8414e..131446ce 100644 --- a/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java +++ b/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java @@ -15,6 +15,7 @@ */ package io.serverlessworkflow.api; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; @@ -39,7 +40,8 @@ private static ObjectMapper configure(ObjectMapper mapper) { return mapper .configure(SerializationFeature.INDENT_OUTPUT, true) .configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false) - .configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false); + .configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } private ObjectMapperFactory() {} diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java index e3c80267..8f43cc5a 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java @@ -6,11 +6,13 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.sun.codemodel.JClass; +import com.sun.codemodel.JClassAlreadyExistsException; import com.sun.codemodel.JClassContainer; import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JFieldVar; import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; +import com.sun.codemodel.JPackage; import com.sun.codemodel.JType; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -48,34 +50,62 @@ public JType apply( unionType("anyOf", nodeName, schemaNode, parent, generatableType, schema, unionTypes); unionType("allOf", nodeName, schemaNode, parent, generatableType, schema, unionTypes); - if (!schemaNode.has("properties") && unionTypes.isEmpty() && refType.isPresent()) { - return refType.get(); - } + JType javaType; + if (schemaNode.has("enum")) { + javaType = + ruleFactory.getEnumRule().apply(nodeName, schemaNode, parent, generatableType, schema); + } else if (!schemaNode.has("properties") && unionTypes.isEmpty() && refType.isPresent()) { + javaType = refType.get(); - JType javaType = - schemaNode.has("enum") - ? ruleFactory.getEnumRule().apply(nodeName, schemaNode, parent, generatableType, schema) - : ruleFactory - .getTypeRule() - .apply(nodeName, schemaNode, parent, generatableType.getPackage(), schema); - - if (javaType instanceof JDefinedClass) { - JDefinedClass definedClass = (JDefinedClass) javaType; - refType.ifPresent( - type -> { - if (type instanceof JClass) { - definedClass._extends((JClass) type); - } else { - wrapIt(definedClass, type); - } - }); - unionTypes.forEach(unionType -> wrapIt(definedClass, unionType)); + } else { + javaType = + ruleFactory + .getTypeRule() + .apply(nodeName, schemaNode, parent, generatableType.getPackage(), schema); + if (javaType instanceof JDefinedClass) { + populateClass((JDefinedClass) javaType, refType, unionTypes); + } else if (isCandidateForCreation(unionTypes)) { + javaType = createUnionClass(nodeName, generatableType.getPackage(), refType, unionTypes); + } + schema.setJavaTypeIfEmpty(javaType); } - schema.setJavaTypeIfEmpty(javaType); - return javaType; } + private boolean isCandidateForCreation(Collection unionTypes) { + return !unionTypes.isEmpty() + && unionTypes.stream() + .allMatch( + o -> + o instanceof JClass + && !((JClass) o).isPrimitive() + && !o.name().equals("String")); + } + + private JDefinedClass populateClass( + JDefinedClass definedClass, Optional refType, Collection unionTypes) { + unionTypes.forEach(unionType -> wrapIt(definedClass, unionType)); + refType.ifPresent( + type -> { + if (type instanceof JClass) { + definedClass._extends((JClass) type); + } else { + wrapIt(definedClass, type); + } + }); + return definedClass; + } + + private JDefinedClass createUnionClass( + String nodeName, JPackage container, Optional refType, Collection unionTypes) { + String className = ruleFactory.getNameHelper().getUniqueClassName(nodeName, null, container); + try { + return populateClass(container._class(className), refType, unionTypes); + } catch (JClassAlreadyExistsException e) { + throw new IllegalArgumentException(e); + } + } + private void wrapIt(JDefinedClass definedClass, JType unionType) { JFieldVar instanceField = definedClass.field( @@ -102,17 +132,17 @@ private void unionType( if (schemaNode.has(prefix)) { int i = 0; for (JsonNode oneOf : (ArrayNode) schemaNode.get(prefix)) { + String ref = parentSchema.getId().toString() + '/' + prefix + '/' + i++; + Schema schema = + ruleFactory + .getSchemaStore() + .create( + URI.create(ref), + ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters()); types.add( - apply( - nodeName, - oneOf, - parent, - generatableType.getPackage(), - ruleFactory - .getSchemaStore() - .create( - URI.create(parentSchema.getId().toString() + '/' + prefix + '/' + i++), - ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters()))); + schema.isGenerated() + ? schema.getJavaType() + : apply(nodeName, oneOf, parent, generatableType.getPackage(), schema)); } } } From 78a598eb40411418c9b582c1c61aebbb5efd96db Mon Sep 17 00:00:00 2001 From: Francisco Javier Tirado Sarti Date: Mon, 24 Jun 2024 12:40:46 +0200 Subject: [PATCH 7/9] [Fix #359] Naming Signed-off-by: Francisco Javier Tirado Sarti --- api/pom.xml | 1 + api/src/main/resources/schema/workflow.yaml | 68 ++++++++++++++----- .../test/resources/features/composite.yaml | 2 +- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 06547db2..5bbaf1ed 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -90,6 +90,7 @@ false true true + true true ${java.version} true diff --git a/api/src/main/resources/schema/workflow.yaml b/api/src/main/resources/schema/workflow.yaml index 88435011..d3a20f2f 100644 --- a/api/src/main/resources/schema/workflow.yaml +++ b/api/src/main/resources/schema/workflow.yaml @@ -54,6 +54,7 @@ properties: type: array items: type: object + title: ExtensionItem minProperties: 1 maxProperties: 1 additionalProperties: @@ -105,6 +106,7 @@ $defs: type: array items: type: object + title: TaskItem minProperties: 1 maxProperties: 1 additionalProperties: @@ -157,6 +159,7 @@ $defs: type: string const: asyncapi with: + title: WithAsyncAPI type: object properties: document: @@ -195,6 +198,7 @@ $defs: type: string const: grpc with: + title: WithGRPC type: object properties: proto: @@ -241,6 +245,7 @@ $defs: type: string const: http with: + title: WithHTTP type: object properties: method: @@ -274,6 +279,7 @@ $defs: type: string const: openapi with: + title: WithOpenAPI type: object properties: document: @@ -441,7 +447,8 @@ $defs: run: type: object oneOf: - - properties: + - title: RunContainer + properties: container: type: object properties: @@ -458,12 +465,14 @@ $defs: type: object description: The container's volume mappings, if any. environment: + title: ContainerEnvironment type: object description: A key/value mapping of the environment variables, if any, to use when running the configured process. required: [ image ] required: [ container ] description: Enables the execution of external processes encapsulated within a containerized environment. - - properties: + - title: RunScript + properties: script: type: object properties: @@ -471,16 +480,19 @@ $defs: type: string description: The language of the script to run. environment: + title: ScriptEnvironment type: object additionalProperties: true description: A key/value mapping of the environment variables, if any, to use when running the configured process. oneOf: - - properties: + - title: ScriptInline + properties: code: type: string required: [ code ] description: The script's code. - - properties: + - title: ScriptExternal + properties: source: $ref: '#/$defs/externalResource' description: The script's resource. @@ -488,7 +500,8 @@ $defs: required: [ language ] required: [ script ] description: Enables the execution of custom scripts or code within a workflow, empowering workflows to perform specialized logic, data processing, or integration tasks by executing user-defined scripts written in various programming languages. - - properties: + - title: RunShell + properties: shell: type: object properties: @@ -496,18 +509,22 @@ $defs: type: string description: The shell command to run. arguments: + title: ShellArguments type: object additionalProperties: true description: A list of the arguments of the shell command to run. environment: + title: ShellEnvironment type: object additionalProperties: true description: A key/value mapping of the environment variables, if any, to use when running the configured process. required: [ command ] required: [ shell ] description: Enables the execution of shell commands within a workflow, enabling workflows to interact with the underlying operating system and perform system-level operations, such as file manipulation, environment configuration, or system administration tasks. - - properties: + - title: RunWokflow + properties: workflow: + title: RunWorkflowDescriptor type: object properties: namespace: @@ -521,6 +538,7 @@ $defs: default: latest description: The version of the workflow to run. Defaults to latest input: + title: WorkflowInput type: object additionalProperties: true description: The data, if any, to pass as input to the workflow to execute. The value should be validated against the target workflow's input schema, if specified. @@ -579,6 +597,7 @@ $defs: type: object properties: errors: + title: CatchErrors type: object as: type: string @@ -615,7 +634,8 @@ $defs: authenticationPolicy: type: object oneOf: - - properties: + - title: BasicAuthenticationPolicy + properties: basic: type: object properties: @@ -628,7 +648,8 @@ $defs: required: [ username, password ] required: [ basic ] description: Use basic authentication. - - properties: + - title: BearerAuthenticationPolicy + properties: bearer: type: object properties: @@ -638,7 +659,8 @@ $defs: required: [ token ] required: [ bearer ] description: Use bearer authentication. - - properties: + - title: OAuth2AuthenticationPolicy + properties: oauth2: type: object properties: @@ -752,21 +774,24 @@ $defs: eventConsumptionStrategy: type: object oneOf: - - properties: + - title: AllEventConsumptionStrategy + properties: all: type: array items: $ref: '#/$defs/eventFilter' description: A list containing all the events that must be consumed. required: [ all ] - - properties: + - title: AnyEventConsumptionStrategy + properties: any: type: array items: $ref: '#/$defs/eventFilter' description: A list containing any of the events to consume. required: [ any ] - - properties: + - title: OneEventConsumptionStrategy + properties: one: $ref: '#/$defs/eventFilter' description: The single event to consume. @@ -775,6 +800,7 @@ $defs: type: object properties: with: + title: WithEvent type: object minProperties: 1 properties: @@ -835,7 +861,8 @@ $defs: oneOf: - type: string format: uri - - type: object + - title: ExternalResourceURI + type: object properties: uri: type: string @@ -895,17 +922,20 @@ $defs: backoff: type: object oneOf: - - properties: + - title: ConstantBackoff + properties: constant: type: object description: The definition of the constant backoff to use, if any. required: [ constant ] - - properties: + - title: ExponentialBackOff + properties: exponential: type: object description: The definition of the exponential backoff to use, if any. required: [ exponential ] - - properties: + - title: LinearBackoff + properties: linear: type: object description: The definition of the linear backoff to use, if any. @@ -947,11 +977,13 @@ $defs: default: json description: The schema's format. Defaults to 'json'. The (optional) version of the format can be set using `{format}:{version}`. oneOf: - - properties: + - title: SchemaInline + properties: document: description: The schema's inline definition. required: [ document ] - - properties: + - title: SchemaExternal + properties: resource: $ref: '#/$defs/externalResource' description: The schema's external resource. diff --git a/api/src/test/resources/features/composite.yaml b/api/src/test/resources/features/composite.yaml index 7ea3b451..91ca1850 100644 --- a/api/src/test/resources/features/composite.yaml +++ b/api/src/test/resources/features/composite.yaml @@ -4,7 +4,7 @@ document: name: do do: - compositeExample: - do: + do: - setRed: set: colors: ${ .colors + ["red"] } From e804006695c982dec181cc64c558d877180dc35e Mon Sep 17 00:00:00 2001 From: Francisco Javier Tirado Sarti Date: Tue, 25 Jun 2024 12:57:37 +0200 Subject: [PATCH 8/9] [Fix #359] Enhacing deserialization Signed-off-by: Francisco Javier Tirado Sarti --- README.md | 2 +- .../api/CallTaskDeserializer.java | 38 ++++++++++++ .../api/CallTaskSerializer.java | 30 ++++++++++ .../api/DeserializeHelper.java | 41 +++++++++++++ .../api/ObjectMapperFactory.java | 11 +++- .../api/SerializeHelper.java | 36 ++++++++++++ .../api/TaskDeserializer.java | 58 +++++++++++++++++++ .../api/TaskSerializer.java | 31 ++++++++++ .../test/resources/features/callOpenAPI.yaml | 4 +- .../test/resources/features/composite.yaml | 12 ++-- .../generator/AllAnyOneOfSchemaRule.java | 27 ++++++++- .../generator/UnevaluatedPropertiesRule.java | 42 ++++++++++++++ .../generator/UnreferencedFactory.java | 21 +++++++ 13 files changed, 340 insertions(+), 13 deletions(-) create mode 100644 api/src/main/java/io/serverlessworkflow/api/CallTaskDeserializer.java create mode 100644 api/src/main/java/io/serverlessworkflow/api/CallTaskSerializer.java create mode 100644 api/src/main/java/io/serverlessworkflow/api/DeserializeHelper.java create mode 100644 api/src/main/java/io/serverlessworkflow/api/SerializeHelper.java create mode 100644 api/src/main/java/io/serverlessworkflow/api/TaskDeserializer.java create mode 100644 api/src/main/java/io/serverlessworkflow/api/TaskSerializer.java create mode 100644 custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java diff --git a/README.md b/README.md index 7e908267..c0b4df70 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Serverless Workflow Java SDK is **not** a workflow runtime implementation but ca | Latest Releases | Conformance to spec version | | :---: | :---: | -| [7.0.0.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/7.0.0.Final) | [v0.10](https://github.com/serverlessworkflow/specification/tree/0.10.x) | +| [7.0.0.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/7.0.0.Final) | [v1.0.0](https://github.com/serverlessworkflow/specification/tree/1.0.x) | | [5.0.0.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/5.0.0.Final) | [v0.8](https://github.com/serverlessworkflow/specification/tree/0.8.x) | | [4.0.5.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/4.0.5.Final) | [v0.8](https://github.com/serverlessworkflow/specification/tree/0.8.x) | | [3.0.0.Final](https://github.com/serverlessworkflow/sdk-java/releases/tag/3.0.0.Final) | [v0.7](https://github.com/serverlessworkflow/specification/tree/0.7.x) | diff --git a/api/src/main/java/io/serverlessworkflow/api/CallTaskDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/CallTaskDeserializer.java new file mode 100644 index 00000000..fcfec397 --- /dev/null +++ b/api/src/main/java/io/serverlessworkflow/api/CallTaskDeserializer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import io.serverlessworkflow.api.types.CallAsyncAPI; +import io.serverlessworkflow.api.types.CallGRPC; +import io.serverlessworkflow.api.types.CallHTTP; +import io.serverlessworkflow.api.types.CallOpenAPI; +import io.serverlessworkflow.api.types.CallTask; +import java.io.IOException; +import java.util.List; + +class CallTaskDeserializer extends JsonDeserializer { + + @Override + public CallTask deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + return DeserializeHelper.deserialize( + p, + CallTask.class, + List.of(CallHTTP.class, CallAsyncAPI.class, CallOpenAPI.class, CallGRPC.class)); + } +} diff --git a/api/src/main/java/io/serverlessworkflow/api/CallTaskSerializer.java b/api/src/main/java/io/serverlessworkflow/api/CallTaskSerializer.java new file mode 100644 index 00000000..18abac33 --- /dev/null +++ b/api/src/main/java/io/serverlessworkflow/api/CallTaskSerializer.java @@ -0,0 +1,30 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import io.serverlessworkflow.api.types.CallTask; +import java.io.IOException; + +class CallTaskSerializer extends JsonSerializer { + @Override + public void serialize(CallTask value, JsonGenerator gen, SerializerProvider serializers) + throws IOException { + SerializeHelper.serialize(gen, value); + } +} diff --git a/api/src/main/java/io/serverlessworkflow/api/DeserializeHelper.java b/api/src/main/java/io/serverlessworkflow/api/DeserializeHelper.java new file mode 100644 index 00000000..ba35b90d --- /dev/null +++ b/api/src/main/java/io/serverlessworkflow/api/DeserializeHelper.java @@ -0,0 +1,41 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.JsonMappingException; +import java.io.IOException; +import java.util.Collection; + +public class DeserializeHelper { + + public static T deserialize( + JsonParser p, Class targetClass, Collection> unionTypes) throws IOException { + TreeNode node = p.readValueAsTree(); + JsonProcessingException ex = new JsonMappingException("Problem deserializing " + targetClass); + for (Class unionType : unionTypes) { + try { + Object object = p.getCodec().treeToValue(node, unionType); + return targetClass.getConstructor(unionType).newInstance(object); + } catch (IOException | ReflectiveOperationException io) { + ex.addSuppressed(io); + } + } + throw ex; + } +} diff --git a/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java index 131446ce..d3a9645c 100644 --- a/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java +++ b/api/src/main/java/io/serverlessworkflow/api/ObjectMapperFactory.java @@ -15,11 +15,13 @@ */ package io.serverlessworkflow.api; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature; +import io.serverlessworkflow.api.types.CallTask; +import io.serverlessworkflow.api.types.Task; class ObjectMapperFactory { @@ -37,11 +39,16 @@ public static final ObjectMapper yamlMapper() { } private static ObjectMapper configure(ObjectMapper mapper) { + SimpleModule simpleModule = new SimpleModule(); + simpleModule.addDeserializer(Task.class, new TaskDeserializer()); + simpleModule.addSerializer(Task.class, new TaskSerializer()); + simpleModule.addDeserializer(CallTask.class, new CallTaskDeserializer()); + simpleModule.addSerializer(CallTask.class, new CallTaskSerializer()); return mapper .configure(SerializationFeature.INDENT_OUTPUT, true) .configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false) .configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + .registerModule(simpleModule); } private ObjectMapperFactory() {} diff --git a/api/src/main/java/io/serverlessworkflow/api/SerializeHelper.java b/api/src/main/java/io/serverlessworkflow/api/SerializeHelper.java new file mode 100644 index 00000000..e08de159 --- /dev/null +++ b/api/src/main/java/io/serverlessworkflow/api/SerializeHelper.java @@ -0,0 +1,36 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import com.fasterxml.jackson.core.JsonGenerator; +import java.io.IOException; +import java.lang.reflect.Method; + +public class SerializeHelper { + public static void serialize(JsonGenerator jgen, Object item) throws IOException { + try { + for (Method m : item.getClass().getDeclaredMethods()) { + Object value = m.invoke(item); + if (value != null) { + jgen.writeObject(value); + break; + } + } + } catch (ReflectiveOperationException ex) { + throw new IOException(ex); + } + } +} diff --git a/api/src/main/java/io/serverlessworkflow/api/TaskDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/TaskDeserializer.java new file mode 100644 index 00000000..d81091ca --- /dev/null +++ b/api/src/main/java/io/serverlessworkflow/api/TaskDeserializer.java @@ -0,0 +1,58 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import io.serverlessworkflow.api.types.CallTask; +import io.serverlessworkflow.api.types.DoTask; +import io.serverlessworkflow.api.types.EmitTask; +import io.serverlessworkflow.api.types.ForTask; +import io.serverlessworkflow.api.types.ForkTask; +import io.serverlessworkflow.api.types.ListenTask; +import io.serverlessworkflow.api.types.RaiseTask; +import io.serverlessworkflow.api.types.RunTask; +import io.serverlessworkflow.api.types.SetTask; +import io.serverlessworkflow.api.types.SwitchTask; +import io.serverlessworkflow.api.types.Task; +import io.serverlessworkflow.api.types.TryTask; +import io.serverlessworkflow.api.types.WaitTask; +import java.io.IOException; +import java.util.List; + +class TaskDeserializer extends JsonDeserializer { + + @Override + public Task deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + return DeserializeHelper.deserialize( + p, + Task.class, + List.of( + CallTask.class, + DoTask.class, + SwitchTask.class, + TryTask.class, + RaiseTask.class, + EmitTask.class, + ForkTask.class, + ForTask.class, + ListenTask.class, + SetTask.class, + RunTask.class, + WaitTask.class)); + } +} diff --git a/api/src/main/java/io/serverlessworkflow/api/TaskSerializer.java b/api/src/main/java/io/serverlessworkflow/api/TaskSerializer.java new file mode 100644 index 00000000..3900f16e --- /dev/null +++ b/api/src/main/java/io/serverlessworkflow/api/TaskSerializer.java @@ -0,0 +1,31 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import io.serverlessworkflow.api.types.Task; +import java.io.IOException; + +class TaskSerializer extends JsonSerializer { + + @Override + public void serialize(Task value, JsonGenerator gen, SerializerProvider serializers) + throws IOException { + SerializeHelper.serialize(gen, value); + } +} diff --git a/api/src/test/resources/features/callOpenAPI.yaml b/api/src/test/resources/features/callOpenAPI.yaml index b83b3f5e..46ecc921 100644 --- a/api/src/test/resources/features/callOpenAPI.yaml +++ b/api/src/test/resources/features/callOpenAPI.yaml @@ -8,8 +8,8 @@ do: with: document: uri: "https://petstore.swagger.io/v2/swagger.json" - operation: findPetsByStatus + operationId: findPetsByStatus parameters: status: ${ .status } output: - from: . | length \ No newline at end of file + as: . | length \ No newline at end of file diff --git a/api/src/test/resources/features/composite.yaml b/api/src/test/resources/features/composite.yaml index 91ca1850..71b0dea4 100644 --- a/api/src/test/resources/features/composite.yaml +++ b/api/src/test/resources/features/composite.yaml @@ -6,11 +6,11 @@ do: - compositeExample: do: - setRed: - set: - colors: ${ .colors + ["red"] } + set: + colors: ${ .colors + ["red"] } - setGreen: - set: - colors: ${ .colors + ["green"] } + set: + colors: ${ .colors + ["green"] } - setBlue: - set: - colors: ${ .colors + ["blue"] } \ No newline at end of file + set: + colors: ${ .colors + ["blue"] } \ No newline at end of file diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java index 8f43cc5a..5f441501 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java @@ -1,14 +1,29 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.serverlessworkflow.generator; import static org.apache.commons.lang3.StringUtils.*; -import com.fasterxml.jackson.annotation.JsonUnwrapped; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.sun.codemodel.JClass; import com.sun.codemodel.JClassAlreadyExistsException; import com.sun.codemodel.JClassContainer; import com.sun.codemodel.JDefinedClass; +import com.sun.codemodel.JExpr; import com.sun.codemodel.JFieldVar; import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; @@ -93,6 +108,10 @@ private JDefinedClass populateClass( wrapIt(definedClass, type); } }); + if (definedClass.constructors().hasNext() + && definedClass.getConstructor(new JType[0]) == null) { + definedClass.constructor(JMod.PUBLIC); + } return definedClass; } @@ -112,13 +131,17 @@ private void wrapIt(JDefinedClass definedClass, JType unionType) { JMod.PRIVATE, unionType, ruleFactory.getNameHelper().getPropertyName(unionType.name(), null)); - instanceField.annotate(JsonUnwrapped.class); JMethod method = definedClass.method( JMod.PUBLIC, unionType, ruleFactory.getNameHelper().getGetterName(unionType.name(), unionType, null)); method.body()._return(instanceField); + JMethod constructor = definedClass.constructor(JMod.PUBLIC); + constructor + .body() + .assign( + JExpr._this().ref(instanceField), constructor.param(unionType, instanceField.name())); } private void unionType( diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java new file mode 100644 index 00000000..b523967b --- /dev/null +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnevaluatedPropertiesRule.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.generator; + +import com.fasterxml.jackson.databind.JsonNode; +import com.sun.codemodel.JDefinedClass; +import org.jsonschema2pojo.Schema; +import org.jsonschema2pojo.rules.AdditionalPropertiesRule; +import org.jsonschema2pojo.rules.Rule; + +public class UnevaluatedPropertiesRule extends AdditionalPropertiesRule + implements Rule { + + public UnevaluatedPropertiesRule(UnreferencedFactory unreferencedFactory) { + super(unreferencedFactory); + } + + public JDefinedClass apply( + String nodeName, JsonNode node, JsonNode parent, JDefinedClass jclass, Schema schema) { + JsonNode unevalutedNode = parent.get("unevaluatedProperties"); + if (unevalutedNode != null && unevalutedNode.isBoolean() && unevalutedNode.asBoolean() == false + || (node == null && parent.has("properties"))) { + // no additional properties allowed + return jclass; + } else { + return super.apply(nodeName, node, parent, jclass, schema); + } + } +} diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java index 3ea9a72f..4726972d 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/UnreferencedFactory.java @@ -1,6 +1,22 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.serverlessworkflow.generator; import com.sun.codemodel.JClassContainer; +import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JType; import org.jsonschema2pojo.rules.Rule; import org.jsonschema2pojo.rules.RuleFactory; @@ -10,4 +26,9 @@ public class UnreferencedFactory extends RuleFactory { public Rule getSchemaRule() { return new AllAnyOneOfSchemaRule(this); } + + @Override + public Rule getAdditionalPropertiesRule() { + return new UnevaluatedPropertiesRule(this); + } } From fd4b7c40467926817289ab694db85f9bcd83778f Mon Sep 17 00:00:00 2001 From: Francisco Javier Tirado Sarti Date: Wed, 26 Jun 2024 09:54:06 +0200 Subject: [PATCH 9/9] [Fix #359] Ricardos comments Signed-off-by: Francisco Javier Tirado Sarti --- api/pom.xml | 5 +++ .../io/serverlessworkflow/api/ApiTest.java | 45 +++++++++++++++++++ custom-generator/pom.xml | 40 ++++++++--------- .../generator/AllAnyOneOfSchemaRule.java | 2 +- pom.xml | 4 +- 5 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 api/src/test/java/io/serverlessworkflow/api/ApiTest.java diff --git a/api/pom.xml b/api/pom.xml index 5bbaf1ed..37524b37 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -50,6 +50,11 @@ junit-jupiter-params test + + org.assertj + assertj-core + test + org.mockito mockito-core diff --git a/api/src/test/java/io/serverlessworkflow/api/ApiTest.java b/api/src/test/java/io/serverlessworkflow/api/ApiTest.java new file mode 100644 index 00000000..87924497 --- /dev/null +++ b/api/src/test/java/io/serverlessworkflow/api/ApiTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2020-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.serverlessworkflow.api; + +import static io.serverlessworkflow.api.WorkflowReader.readWorkflowFromClasspath; +import static org.assertj.core.api.Assertions.assertThat; + +import io.serverlessworkflow.api.types.CallHTTP; +import io.serverlessworkflow.api.types.CallTask; +import io.serverlessworkflow.api.types.Task; +import io.serverlessworkflow.api.types.Workflow; +import java.io.IOException; +import org.junit.jupiter.api.Test; + +public class ApiTest { + + @Test + void testCallHTTPAPI() throws IOException { + Workflow workflow = readWorkflowFromClasspath("features/callHttp.yaml"); + assertThat(workflow.getDo()).isNotEmpty(); + assertThat(workflow.getDo().get(0).getAdditionalProperties()).isNotEmpty(); + assertThat(workflow.getDo().get(0).getAdditionalProperties().values()).isNotEmpty(); + Task task = workflow.getDo().get(0).getAdditionalProperties().values().iterator().next(); + CallTask callTask = task.getCallTask(); + assertThat(callTask).isNotNull(); + assertThat(task.getDoTask()).isNull(); + CallHTTP httpCall = callTask.getCallHTTP(); + assertThat(httpCall).isNotNull(); + assertThat(callTask.getCallAsyncAPI()).isNull(); + assertThat(httpCall.getWith().getMethod()).isEqualTo("get"); + } +} diff --git a/custom-generator/pom.xml b/custom-generator/pom.xml index c48b5bfa..7aaedbda 100644 --- a/custom-generator/pom.xml +++ b/custom-generator/pom.xml @@ -14,26 +14,26 @@ - - com.spotify.fmt - fmt-maven-plugin - - src/main/java - src/test/java - false - .*\.java - false - false - - - - - - format - - - - + + com.spotify.fmt + fmt-maven-plugin + + src/main/java + src/test/java + false + .*\.java + false + false + + + + + + format + + + + \ No newline at end of file diff --git a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java index 5f441501..e16e07bc 100644 --- a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java +++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java @@ -207,7 +207,7 @@ private String nameFromRef(String ref, String nodeName) { if (!ref.contains("#")) { nameFromRef = Jsonschema2Pojo.getNodeName(ref, ruleFactory.getGenerationConfig()); } else { - String[] nameParts = split(ref, "/\\#"); + String[] nameParts = ref.split("[/\\#]"); nameFromRef = nameParts[nameParts.length - 1]; } diff --git a/pom.xml b/pom.xml index 3cb9c69d..6635b583 100644 --- a/pom.xml +++ b/pom.xml @@ -50,10 +50,10 @@ 3.2.0 - 3.3.1 + 3.4.0 3.13.0 3.1.2 - 3.0.0-M2 + 3.5.0 3.2.5 2.23 3.2.4