diff --git a/.github/project.yml b/.github/project.yml
index e787d911..1d03de1c 100644
--- a/.github/project.yml
+++ b/.github/project.yml
@@ -1,4 +1,4 @@
# Retriggering release again
release:
- current-version: 7.0.0.Final
+ current-version: 7.1.0.Final
next-version: 8.0.0-SNAPSHOT
diff --git a/api/pom.xml b/api/pom.xml
index 69f8c2f5..9f0802fe 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -4,7 +4,7 @@
io.serverlessworkflow
serverlessworkflow-parent
- 8.0.0-SNAPSHOT
+ 7.1.0.Final
serverlessworkflow-api
@@ -40,10 +40,12 @@
org.hibernate.validator
hibernate-validator
+ runtime
org.glassfish.expressly
expressly
+ runtime
diff --git a/api/src/main/resources/schema/workflow.yaml b/api/src/main/resources/schema/workflow.yaml
index b59e2f3a..73bda7ee 100644
--- a/api/src/main/resources/schema/workflow.yaml
+++ b/api/src/main/resources/schema/workflow.yaml
@@ -1,4 +1,4 @@
-$id: https://serverlessworkflow.io/schemas/1.0.0-alpha5/workflow.yaml
+$id: https://serverlessworkflow.io/schemas/1.0.1/workflow.yaml
$schema: https://json-schema.org/draft/2020-12/schema
description: Serverless Workflow DSL - Workflow Schema.
type: object
@@ -226,638 +226,664 @@ $defs:
oneOf:
- title: CallAsyncAPI
description: Defines the AsyncAPI call to perform.
- $ref: '#/$defs/taskBase'
type: object
required: [ call, with ]
unevaluatedProperties: false
- properties:
- call:
- type: string
- const: asyncapi
- with:
- type: object
- title: AsyncApiArguments
- description: The Async API call arguments.
- properties:
- document:
- $ref: '#/$defs/externalResource'
- title: AsyncAPIDocument
- description: The document that defines the AsyncAPI operation to call.
- channel:
- type: string
- title: With
- description: The name of the channel on which to perform the operation. Used only in case the referenced document uses AsyncAPI v2.6.0.
- operation:
- type: string
- title: AsyncAPIOperation
- description: A reference to the AsyncAPI operation to call.
- server:
- $ref: '#/$defs/asyncApiServer'
- title: AsyncAPIServer
- description: An object used to configure to the server to call the specified AsyncAPI operation on.
- protocol:
- type: string
- title: AsyncApiProtocol
- description: The protocol to use to select the target server.
- enum: [ amqp, amqp1, anypointmq, googlepubsub, http, ibmmq, jms, kafka, mercure, mqtt, mqtt5, nats, pulsar, redis, sns, solace, sqs, stomp, ws ]
- message:
- $ref: '#/$defs/asyncApiOutboundMessage'
- title: AsyncApiMessage
- description: An object used to configure the message to publish using the target operation.
- subscription:
- $ref: '#/$defs/asyncApiSubscription'
- title: AsyncApiSubscription
- description: An object used to configure the subscription to messages consumed using the target operation.
- authentication:
- $ref: '#/$defs/referenceableAuthenticationPolicy'
- title: AsyncAPIAuthentication
- description: The authentication policy, if any, to use when calling the AsyncAPI operation.
- oneOf:
- - required: [ document, operation, message ]
- - required: [ document, operation, subscription ]
- - required: [ document, channel, message ]
- - required: [ document, channel, subscription ]
- unevaluatedProperties: false
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ call:
+ type: string
+ const: asyncapi
+ with:
+ type: object
+ title: AsyncApiArguments
+ description: The Async API call arguments.
+ properties:
+ document:
+ $ref: '#/$defs/externalResource'
+ title: AsyncAPIDocument
+ description: The document that defines the AsyncAPI operation to call.
+ channel:
+ type: string
+ title: With
+ description: The name of the channel on which to perform the operation. Used only in case the referenced document uses AsyncAPI v2.6.0.
+ operation:
+ type: string
+ title: AsyncAPIOperation
+ description: A reference to the AsyncAPI operation to call.
+ server:
+ $ref: '#/$defs/asyncApiServer'
+ title: AsyncAPIServer
+ description: An object used to configure to the server to call the specified AsyncAPI operation on.
+ protocol:
+ type: string
+ title: AsyncApiProtocol
+ description: The protocol to use to select the target server.
+ enum: [ amqp, amqp1, anypointmq, googlepubsub, http, ibmmq, jms, kafka, mercure, mqtt, mqtt5, nats, pulsar, redis, sns, solace, sqs, stomp, ws ]
+ message:
+ $ref: '#/$defs/asyncApiOutboundMessage'
+ title: AsyncApiMessage
+ description: An object used to configure the message to publish using the target operation.
+ subscription:
+ $ref: '#/$defs/asyncApiSubscription'
+ title: AsyncApiSubscription
+ description: An object used to configure the subscription to messages consumed using the target operation.
+ authentication:
+ $ref: '#/$defs/referenceableAuthenticationPolicy'
+ title: AsyncAPIAuthentication
+ description: The authentication policy, if any, to use when calling the AsyncAPI operation.
+ oneOf:
+ - required: [ document, operation, message ]
+ - required: [ document, operation, subscription ]
+ - required: [ document, channel, message ]
+ - required: [ document, channel, subscription ]
+ unevaluatedProperties: false
- title: CallGRPC
description: Defines the GRPC call to perform.
- $ref: '#/$defs/taskBase'
type: object
unevaluatedProperties: false
required: [ call, with ]
- properties:
- call:
- type: string
- const: grpc
- with:
- type: object
- title: GRPCArguments
- description: The GRPC call arguments.
- properties:
- proto:
- $ref: '#/$defs/externalResource'
- title: WithGRPCProto
- description: The proto resource that describes the GRPC service to call.
- service:
- type: object
- title: WithGRPCService
- unevaluatedProperties: false
- properties:
- name:
- type: string
- title: WithGRPCServiceName
- description: The name of the GRPC service to call.
- host:
- type: string
- title: WithGRPCServiceHost
- description: The hostname of the GRPC service to call.
- pattern: ^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$
- port:
- type: integer
- title: WithGRPCServicePost
- description: The port number of the GRPC service to call.
- minimum: 0
- maximum: 65535
- authentication:
- $ref: '#/$defs/referenceableAuthenticationPolicy'
- title: WithGRPCServiceAuthentication
- description: The endpoint's authentication policy, if any.
- required: [ name, host ]
- method:
- type: string
- title: WithGRPCMethod
- description: The name of the method to call on the defined GRPC service.
- arguments:
- type: object
- title: WithGRPCArguments
- description: The arguments, if any, to call the method with.
- additionalProperties: true
- required: [ proto, service, method ]
- unevaluatedProperties: false
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ call:
+ type: string
+ const: grpc
+ with:
+ type: object
+ title: GRPCArguments
+ description: The GRPC call arguments.
+ properties:
+ proto:
+ $ref: '#/$defs/externalResource'
+ title: WithGRPCProto
+ description: The proto resource that describes the GRPC service to call.
+ service:
+ type: object
+ title: WithGRPCService
+ unevaluatedProperties: false
+ properties:
+ name:
+ type: string
+ title: WithGRPCServiceName
+ description: The name of the GRPC service to call.
+ host:
+ type: string
+ title: WithGRPCServiceHost
+ description: The hostname of the GRPC service to call.
+ pattern: ^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$
+ port:
+ type: integer
+ title: WithGRPCServicePost
+ description: The port number of the GRPC service to call.
+ minimum: 0
+ maximum: 65535
+ authentication:
+ $ref: '#/$defs/referenceableAuthenticationPolicy'
+ title: WithGRPCServiceAuthentication
+ description: The endpoint's authentication policy, if any.
+ required: [ name, host ]
+ method:
+ type: string
+ title: WithGRPCMethod
+ description: The name of the method to call on the defined GRPC service.
+ arguments:
+ type: object
+ title: WithGRPCArguments
+ description: The arguments, if any, to call the method with.
+ additionalProperties: true
+ required: [ proto, service, method ]
+ unevaluatedProperties: false
- title: CallHTTP
description: Defines the HTTP call to perform.
- $ref: '#/$defs/taskBase'
type: object
unevaluatedProperties: false
required: [ call, with ]
- properties:
- call:
- type: string
- const: http
- with:
- type: object
- title: HTTPArguments
- description: The HTTP call arguments.
- properties:
- method:
- type: string
- title: HTTPMethod
- description: The HTTP method of the HTTP request to perform.
- endpoint:
- title: HTTPEndpoint
- description: The HTTP endpoint to send the request to.
- $ref: '#/$defs/endpoint'
- headers:
- type: object
- title: HTTPHeaders
- description: A name/value mapping of the headers, if any, of the HTTP request to perform.
- body:
- title: HTTPBody
- description: The body, if any, of the HTTP request to perform.
- query:
- type: object
- title: HTTPQuery
- description: A name/value mapping of the query parameters, if any, of the HTTP request to perform.
- additionalProperties: true
- output:
- type: string
- title: HTTPOutput
- description: The http call output format. Defaults to 'content'.
- enum: [ raw, content, response ]
- redirect:
- type: boolean
- title: HttpRedirect
- description: Specifies whether redirection status codes (`300–399`) should be treated as errors.
- required: [ method, endpoint ]
- unevaluatedProperties: false
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ call:
+ type: string
+ const: http
+ with:
+ type: object
+ title: HTTPArguments
+ description: The HTTP call arguments.
+ properties:
+ method:
+ type: string
+ title: HTTPMethod
+ description: The HTTP method of the HTTP request to perform.
+ endpoint:
+ title: HTTPEndpoint
+ description: The HTTP endpoint to send the request to.
+ $ref: '#/$defs/endpoint'
+ headers:
+ oneOf:
+ - type: object
+ additionalProperties:
+ type: string
+ - $ref: '#/$defs/runtimeExpression'
+ title: HTTPHeaders
+ description: A name/value mapping of the headers, if any, of the HTTP request to perform.
+ body:
+ title: HTTPBody
+ description: The body, if any, of the HTTP request to perform.
+ query:
+ oneOf:
+ - type: object
+ additionalProperties:
+ type: string
+ - $ref: '#/$defs/runtimeExpression'
+ title: HTTPQuery
+ description: A name/value mapping of the query parameters, if any, of the HTTP request to perform.
+ additionalProperties: true
+ output:
+ type: string
+ title: HTTPOutput
+ description: The http call output format. Defaults to 'content'.
+ enum: [ raw, content, response ]
+ redirect:
+ type: boolean
+ title: HttpRedirect
+ description: Specifies whether redirection status codes (`300–399`) should be treated as errors.
+ required: [ method, endpoint ]
+ unevaluatedProperties: false
- title: CallOpenAPI
description: Defines the OpenAPI call to perform.
- $ref: '#/$defs/taskBase'
type: object
unevaluatedProperties: false
required: [ call, with ]
- properties:
- call:
- type: string
- const: openapi
- with:
- type: object
- title: OpenAPIArguments
- description: The OpenAPI call arguments.
- properties:
- document:
- $ref: '#/$defs/externalResource'
- title: WithOpenAPIDocument
- description: The document that defines the OpenAPI operation to call.
- operationId:
- type: string
- title: WithOpenAPIOperation
- description: The id of the OpenAPI operation to call.
- parameters:
- type: object
- title: WithOpenAPIParameters
- description: A name/value mapping of the parameters of the OpenAPI operation to call.
- additionalProperties: true
- authentication:
- $ref: '#/$defs/referenceableAuthenticationPolicy'
- title: WithOpenAPIAuthentication
- description: The authentication policy, if any, to use when calling the OpenAPI operation.
- output:
- type: string
- enum: [ raw, content, response ]
- title: WithOpenAPIOutput
- description: The http call output format. Defaults to 'content'.
- redirect:
- type: boolean
- title: HttpRedirect
- description: Specifies whether redirection status codes (`300–399`) should be treated as errors.
- required: [ document, operationId ]
- unevaluatedProperties: false
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ call:
+ type: string
+ const: openapi
+ with:
+ type: object
+ title: OpenAPIArguments
+ description: The OpenAPI call arguments.
+ properties:
+ document:
+ $ref: '#/$defs/externalResource'
+ title: WithOpenAPIDocument
+ description: The document that defines the OpenAPI operation to call.
+ operationId:
+ type: string
+ title: WithOpenAPIOperation
+ description: The id of the OpenAPI operation to call.
+ parameters:
+ type: object
+ title: WithOpenAPIParameters
+ description: A name/value mapping of the parameters of the OpenAPI operation to call.
+ additionalProperties: true
+ authentication:
+ $ref: '#/$defs/referenceableAuthenticationPolicy'
+ title: WithOpenAPIAuthentication
+ description: The authentication policy, if any, to use when calling the OpenAPI operation.
+ output:
+ type: string
+ enum: [ raw, content, response ]
+ title: WithOpenAPIOutput
+ description: The http call output format. Defaults to 'content'.
+ redirect:
+ type: boolean
+ title: HttpRedirect
+ description: Specifies whether redirection status codes (`300–399`) should be treated as errors.
+ required: [ document, operationId ]
+ unevaluatedProperties: false
- title: CallFunction
description: Defines the function call to perform.
- $ref: '#/$defs/taskBase'
type: object
unevaluatedProperties: false
required: [ call ]
- properties:
- call:
- type: string
- not:
- enum: ["asyncapi", "grpc", "http", "openapi"]
- description: The name of the function to call.
- with:
- type: object
- title: FunctionArguments
- description: A name/value mapping of the parameters, if any, to call the function with.
- additionalProperties: true
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ call:
+ type: string
+ not:
+ enum: ["asyncapi", "grpc", "http", "openapi"]
+ description: The name of the function to call.
+ with:
+ type: object
+ title: FunctionArguments
+ description: A name/value mapping of the parameters, if any, to call the function with.
+ additionalProperties: true
forkTask:
type: object
- $ref: '#/$defs/taskBase'
title: 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.
unevaluatedProperties: false
required: [ fork ]
- properties:
- fork:
- type: object
- title: ForkTaskConfiguration
- description: The configuration of the branches to perform concurrently.
- unevaluatedProperties: false
- required: [ branches ]
- properties:
- branches:
- $ref: '#/$defs/taskList'
- title: ForkBranches
- compete:
- type: boolean
- title: ForkCompete
- 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.
- default: false
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ fork:
+ type: object
+ title: ForkTaskConfiguration
+ description: The configuration of the branches to perform concurrently.
+ unevaluatedProperties: false
+ required: [ branches ]
+ properties:
+ branches:
+ $ref: '#/$defs/taskList'
+ title: ForkBranches
+ compete:
+ type: boolean
+ title: ForkCompete
+ 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.
+ default: false
doTask:
type: object
- $ref: '#/$defs/taskBase'
title: DoTask
description: Allows to execute a list of tasks in sequence.
unevaluatedProperties: false
required: [ do ]
- properties:
- do:
- $ref: '#/$defs/taskList'
- title: DoTaskConfiguration
- description: The configuration of the tasks to perform sequentially.
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ do:
+ $ref: '#/$defs/taskList'
+ title: DoTaskConfiguration
+ description: The configuration of the tasks to perform sequentially.
emitTask:
type: object
- $ref: '#/$defs/taskBase'
title: EmitTask
description: Allows workflows to publish events to event brokers or messaging systems, facilitating communication and coordination between different components and services.
required: [ emit ]
unevaluatedProperties: false
- properties:
- emit:
- type: object
- title: EmitTaskConfiguration
- description: The configuration of an event's emission.
- unevaluatedProperties: false
- properties:
- event:
- type: object
- title: EmitEventDefinition
- description: The definition of the event to emit.
- properties:
- with:
- $ref: '#/$defs/eventProperties'
- title: EmitEventWith
- description: Defines the properties of event to emit.
- required: [ source, type ]
- additionalProperties: true
- required: [ event ]
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ emit:
+ type: object
+ title: EmitTaskConfiguration
+ description: The configuration of an event's emission.
+ unevaluatedProperties: false
+ properties:
+ event:
+ type: object
+ title: EmitEventDefinition
+ description: The definition of the event to emit.
+ properties:
+ with:
+ $ref: '#/$defs/eventProperties'
+ title: EmitEventWith
+ description: Defines the properties of event to emit.
+ required: [ source, type ]
+ additionalProperties: true
+ required: [ event ]
forTask:
type: object
- $ref: '#/$defs/taskBase'
title: 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.
required: [ for, do ]
unevaluatedProperties: false
- properties:
- for:
- type: object
- title: ForTaskConfiguration
- description: The definition of the loop that iterates over a range of values.
- unevaluatedProperties: false
- properties:
- each:
- type: string
- title: ForEach
- description: The name of the variable used to store the current item being enumerated.
- default: item
- in:
- type: string
- title: ForIn
- description: A runtime expression used to get the collection to enumerate.
- at:
- type: string
- title: ForAt
- description: The name of the variable used to store the index of the current item being enumerated.
- default: index
- required: [ in ]
- while:
- type: string
- title: While
- description: A runtime expression that represents the condition, if any, that must be met for the iteration to continue.
- do:
- $ref: '#/$defs/taskList'
- title: ForTaskDo
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ for:
+ type: object
+ title: ForTaskConfiguration
+ description: The definition of the loop that iterates over a range of values.
+ unevaluatedProperties: false
+ properties:
+ each:
+ type: string
+ title: ForEach
+ description: The name of the variable used to store the current item being enumerated.
+ default: item
+ in:
+ type: string
+ title: ForIn
+ description: A runtime expression used to get the collection to enumerate.
+ at:
+ type: string
+ title: ForAt
+ description: The name of the variable used to store the index of the current item being enumerated.
+ default: index
+ required: [ in ]
+ while:
+ type: string
+ title: While
+ description: A runtime expression that represents the condition, if any, that must be met for the iteration to continue.
+ do:
+ $ref: '#/$defs/taskList'
+ title: ForTaskDo
listenTask:
type: object
- $ref: '#/$defs/taskBase'
title: ListenTask
description: Provides a mechanism for workflows to await and react to external events, enabling event-driven behavior within workflow systems.
required: [ listen ]
unevaluatedProperties: false
- properties:
- listen:
- type: object
- title: ListenTaskConfiguration
- description: The configuration of the listener to use.
- unevaluatedProperties: false
- properties:
- to:
- $ref: '#/$defs/eventConsumptionStrategy'
- title: ListenTo
- description: Defines the event(s) to listen to.
- read:
- type: string
- enum: [ data, envelope, raw ]
- default: data
- title: ListenAndReadAs
- description: Specifies how events are read during the listen operation.
- required: [ to ]
- foreach:
- $ref: '#/$defs/subscriptionIterator'
- title: ListenIterator
- description: Configures the iterator, if any, for processing consumed event(s).
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ listen:
+ type: object
+ title: ListenTaskConfiguration
+ description: The configuration of the listener to use.
+ unevaluatedProperties: false
+ properties:
+ to:
+ $ref: '#/$defs/eventConsumptionStrategy'
+ title: ListenTo
+ description: Defines the event(s) to listen to.
+ read:
+ type: string
+ enum: [ data, envelope, raw ]
+ default: data
+ title: ListenAndReadAs
+ description: Specifies how events are read during the listen operation.
+ required: [ to ]
+ foreach:
+ $ref: '#/$defs/subscriptionIterator'
+ title: ListenIterator
+ description: Configures the iterator, if any, for processing consumed event(s).
raiseTask:
type: object
- $ref: '#/$defs/taskBase'
title: RaiseTask
description: Intentionally triggers and propagates errors.
required: [ raise ]
unevaluatedProperties: false
- properties:
- raise:
- type: object
- title: RaiseTaskConfiguration
- description: The definition of the error to raise.
- unevaluatedProperties: false
- properties:
- error:
- title: RaiseTaskError
- oneOf:
- - $ref: '#/$defs/error'
- title: RaiseErrorDefinition
- description: Defines the error to raise.
- - type: string
- title: RaiseErrorReference
- description: The name of the error to raise
- required: [ error ]
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ raise:
+ type: object
+ title: RaiseTaskConfiguration
+ description: The definition of the error to raise.
+ unevaluatedProperties: false
+ properties:
+ error:
+ title: RaiseTaskError
+ oneOf:
+ - $ref: '#/$defs/error'
+ title: RaiseErrorDefinition
+ description: Defines the error to raise.
+ - type: string
+ title: RaiseErrorReference
+ description: The name of the error to raise
+ required: [ error ]
runTask:
type: object
- $ref: '#/$defs/taskBase'
title: RunTask
description: Provides the capability to execute external containers, shell commands, scripts, or workflows.
required: [ run ]
unevaluatedProperties: false
- properties:
- run:
- type: object
- title: RunTaskConfiguration
- description: The configuration of the process to execute.
- unevaluatedProperties: false
- properties:
- await:
- type: boolean
- default: true
- title: AwaitProcessCompletion
- description: Whether to await the process completion before continuing.
- return:
- type: string
- title: ProcessReturnType
- description: Configures the output of the process.
- enum: [ stdout, stderr, code, all, none ]
- default: stdout
- oneOf:
- - title: RunContainer
- description: Enables the execution of external processes encapsulated within a containerized environment.
- properties:
- container:
- type: object
- title: Container
- description: The configuration of the container to run.
- unevaluatedProperties: false
- properties:
- image:
- type: string
- title: ContainerImage
- description: The name of the container image to run.
- name:
- type: string
- title: ContainerName
- description: A runtime expression, if any, used to give specific name to the container.
- command:
- type: string
- title: ContainerCommand
- description: The command, if any, to execute on the container.
- ports:
- type: object
- title: ContainerPorts
- description: The container's port mappings, if any.
- volumes:
- type: object
- title: ContainerVolumes
- description: The container's volume mappings, if any.
- environment:
- type: object
- title: ContainerEnvironment
- description: A key/value mapping of the environment variables, if any, to use when running the configured process.
- lifetime:
- $ref: '#/$defs/containerLifetime'
- title: ContainerLifetime
- description: An object, if any, used to configure the container's lifetime
- required: [ image ]
- required: [ container ]
- - title: RunScript
- 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:
- script:
- type: object
- title: Script
- description: The configuration of the script to run.
- unevaluatedProperties: false
- properties:
- language:
- type: string
- title: ScriptLanguage
- description: The language of the script to run.
- arguments:
- type: object
- title: ScriptArguments
- description: A key/value mapping of the arguments, if any, to use when running the configured script.
- additionalProperties: true
- environment:
- type: object
- title: ScriptEnvironment
- description: A key/value mapping of the environment variables, if any, to use when running the configured script process.
- additionalProperties: true
- oneOf:
- - title: InlineScript
- type: object
- description: The script's code.
- properties:
- code:
- type: string
- title: InlineScriptCode
- required: [ code ]
- - title: ExternalScript
- type: object
- description: The script's resource.
- properties:
- source:
- $ref: '#/$defs/externalResource'
- title: ExternalScriptResource
- required: [ source ]
- required: [ language ]
- required: [ script ]
- - title: RunShell
- 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:
- shell:
- type: object
- title: Shell
- description: The configuration of the shell command to run.
- unevaluatedProperties: false
- properties:
- command:
- type: string
- title: ShellCommand
- description: The shell command to run.
- arguments:
- type: object
- title: ShellArguments
- description: A list of the arguments of the shell command to run.
- additionalProperties: true
- environment:
- type: object
- title: ShellEnvironment
- description: A key/value mapping of the environment variables, if any, to use when running the configured process.
- additionalProperties: true
- required: [ command ]
- required: [ shell ]
- - title: RunWorkflow
- 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.
- properties:
- workflow:
- type: object
- title: SubflowConfiguration
- description: The configuration of the workflow to run.
- unevaluatedProperties: false
- properties:
- namespace:
- type: string
- title: SubflowNamespace
- description: The namespace the workflow to run belongs to.
- name:
- type: string
- title: SubflowName
- description: The name of the workflow to run.
- version:
- type: string
- default: latest
- title: SubflowVersion
- description: The version of the workflow to run. Defaults to latest.
- input:
- type: object
- title: SubflowInput
- 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.
- additionalProperties: true
- required: [ namespace, name, version ]
- required: [ workflow ]
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ run:
+ type: object
+ title: RunTaskConfiguration
+ description: The configuration of the process to execute.
+ unevaluatedProperties: false
+ properties:
+ await:
+ type: boolean
+ default: true
+ title: AwaitProcessCompletion
+ description: Whether to await the process completion before continuing.
+ return:
+ type: string
+ title: ProcessReturnType
+ description: Configures the output of the process.
+ enum: [ stdout, stderr, code, all, none ]
+ default: stdout
+ oneOf:
+ - title: RunContainer
+ description: Enables the execution of external processes encapsulated within a containerized environment.
+ properties:
+ container:
+ type: object
+ title: Container
+ description: The configuration of the container to run.
+ unevaluatedProperties: false
+ properties:
+ image:
+ type: string
+ title: ContainerImage
+ description: The name of the container image to run.
+ name:
+ type: string
+ title: ContainerName
+ description: A runtime expression, if any, used to give specific name to the container.
+ command:
+ type: string
+ title: ContainerCommand
+ description: The command, if any, to execute on the container.
+ ports:
+ type: object
+ title: ContainerPorts
+ description: The container's port mappings, if any.
+ volumes:
+ type: object
+ title: ContainerVolumes
+ description: The container's volume mappings, if any.
+ environment:
+ type: object
+ title: ContainerEnvironment
+ description: A key/value mapping of the environment variables, if any, to use when running the configured process.
+ lifetime:
+ $ref: '#/$defs/containerLifetime'
+ title: ContainerLifetime
+ description: An object, if any, used to configure the container's lifetime
+ required: [ image ]
+ required: [ container ]
+ - title: RunScript
+ 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:
+ script:
+ type: object
+ title: Script
+ description: The configuration of the script to run.
+ unevaluatedProperties: false
+ properties:
+ language:
+ type: string
+ title: ScriptLanguage
+ description: The language of the script to run.
+ arguments:
+ type: object
+ title: ScriptArguments
+ description: A key/value mapping of the arguments, if any, to use when running the configured script.
+ additionalProperties: true
+ environment:
+ type: object
+ title: ScriptEnvironment
+ description: A key/value mapping of the environment variables, if any, to use when running the configured script process.
+ additionalProperties: true
+ oneOf:
+ - title: InlineScript
+ type: object
+ description: The script's code.
+ properties:
+ code:
+ type: string
+ title: InlineScriptCode
+ required: [ code ]
+ - title: ExternalScript
+ type: object
+ description: The script's resource.
+ properties:
+ source:
+ $ref: '#/$defs/externalResource'
+ title: ExternalScriptResource
+ required: [ source ]
+ required: [ language ]
+ required: [ script ]
+ - title: RunShell
+ 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:
+ shell:
+ type: object
+ title: Shell
+ description: The configuration of the shell command to run.
+ unevaluatedProperties: false
+ properties:
+ command:
+ type: string
+ title: ShellCommand
+ description: The shell command to run.
+ arguments:
+ type: object
+ title: ShellArguments
+ description: A list of the arguments of the shell command to run.
+ additionalProperties: true
+ environment:
+ type: object
+ title: ShellEnvironment
+ description: A key/value mapping of the environment variables, if any, to use when running the configured process.
+ additionalProperties: true
+ required: [ command ]
+ required: [ shell ]
+ - title: RunWorkflow
+ 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.
+ properties:
+ workflow:
+ type: object
+ title: SubflowConfiguration
+ description: The configuration of the workflow to run.
+ unevaluatedProperties: false
+ properties:
+ namespace:
+ type: string
+ title: SubflowNamespace
+ description: The namespace the workflow to run belongs to.
+ name:
+ type: string
+ title: SubflowName
+ description: The name of the workflow to run.
+ version:
+ type: string
+ default: latest
+ title: SubflowVersion
+ description: The version of the workflow to run. Defaults to latest.
+ input:
+ type: object
+ title: SubflowInput
+ 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.
+ additionalProperties: true
+ required: [ namespace, name, version ]
+ required: [ workflow ]
setTask:
type: object
- $ref: '#/$defs/taskBase'
title: SetTask
description: A task used to set data.
required: [ set ]
unevaluatedProperties: false
- properties:
- set:
- type: object
- title: SetTaskConfiguration
- description: The data to set.
- minProperties: 1
- additionalProperties: true
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ set:
+ oneOf:
+ - type: object
+ minProperties: 1
+ additionalProperties: true
+ - type: string
+ title: SetTaskConfiguration
+ description: The data to set.
switchTask:
type: object
- $ref: '#/$defs/taskBase'
title: SwitchTask
description: Enables conditional branching within workflows, allowing them to dynamically select different paths based on specified conditions or criteria.
required: [ switch ]
unevaluatedProperties: false
- properties:
- switch:
- type: array
- title: SwitchTaskConfiguration
- description: The definition of the switch to use.
- minItems: 1
- items:
- type: object
- title: SwitchItem
- minProperties: 1
- maxProperties: 1
- additionalProperties:
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ switch:
+ type: array
+ title: SwitchTaskConfiguration
+ description: The definition of the switch to use.
+ minItems: 1
+ items:
type: object
- title: SwitchCase
- description: The definition of a case within a switch task, defining a condition and corresponding tasks to execute if the condition is met.
- unevaluatedProperties: false
- required: [ then ]
- properties:
- when:
- type: string
- title: SwitchCaseCondition
- description: A runtime expression used to determine whether or not the case matches.
- then:
- $ref: '#/$defs/flowDirective'
- title: SwitchCaseOutcome
- description: The flow directive to execute when the case matches.
+ title: SwitchItem
+ minProperties: 1
+ maxProperties: 1
+ additionalProperties:
+ type: object
+ title: SwitchCase
+ description: The definition of a case within a switch task, defining a condition and corresponding tasks to execute if the condition is met.
+ unevaluatedProperties: false
+ required: [ then ]
+ properties:
+ when:
+ type: string
+ title: SwitchCaseCondition
+ description: A runtime expression used to determine whether or not the case matches.
+ then:
+ $ref: '#/$defs/flowDirective'
+ title: SwitchCaseOutcome
+ description: The flow directive to execute when the case matches.
tryTask:
type: object
- $ref: '#/$defs/taskBase'
title: TryTask
description: Serves as a mechanism within workflows to handle errors gracefully, potentially retrying failed tasks before proceeding with alternate ones.
required: [ try, catch ]
unevaluatedProperties: false
- properties:
- try:
- $ref: '#/$defs/taskList'
- title: TryTaskConfiguration
- description: The task(s) to perform.
- catch:
- type: object
- title: TryTaskCatch
- description: The object used to define the errors to catch.
- unevaluatedProperties: false
- properties:
- errors:
- type: object
- title: CatchErrors
- properties:
- with:
- $ref: '#/$defs/errorFilter'
- description: static error filter
- as:
- type: string
- title: CatchAs
- description: The name of the runtime expression variable to save the error as. Defaults to 'error'.
- when:
- type: string
- title: CatchWhen
- description: A runtime expression used to determine whether to catch the filtered error.
- exceptWhen:
- type: string
- title: CatchExceptWhen
- description: A runtime expression used to determine whether not to catch the filtered error.
- retry:
- oneOf:
- - $ref: '#/$defs/retryPolicy'
- title: RetryPolicyDefinition
- description: The retry policy to use, if any, when catching errors.
- - type: string
- title: RetryPolicyReference
- description: The name of the retry policy to use, if any, when catching errors.
- do:
- $ref: '#/$defs/taskList'
- title: TryTaskCatchDo
- description: The definition of the task(s) to run when catching an error.
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ try:
+ $ref: '#/$defs/taskList'
+ title: TryTaskConfiguration
+ description: The task(s) to perform.
+ catch:
+ type: object
+ title: TryTaskCatch
+ description: The object used to define the errors to catch.
+ unevaluatedProperties: false
+ properties:
+ errors:
+ type: object
+ title: CatchErrors
+ properties:
+ with:
+ $ref: '#/$defs/errorFilter'
+ description: static error filter
+ as:
+ type: string
+ title: CatchAs
+ description: The name of the runtime expression variable to save the error as. Defaults to 'error'.
+ when:
+ type: string
+ title: CatchWhen
+ description: A runtime expression used to determine whether to catch the filtered error.
+ exceptWhen:
+ type: string
+ title: CatchExceptWhen
+ description: A runtime expression used to determine whether not to catch the filtered error.
+ retry:
+ oneOf:
+ - $ref: '#/$defs/retryPolicy'
+ title: RetryPolicyDefinition
+ description: The retry policy to use, if any, when catching errors.
+ - type: string
+ title: RetryPolicyReference
+ description: The name of the retry policy to use, if any, when catching errors.
+ do:
+ $ref: '#/$defs/taskList'
+ title: TryTaskCatchDo
+ description: The definition of the task(s) to run when catching an error.
waitTask:
type: object
- $ref: '#/$defs/taskBase'
title: WaitTask
description: Allows workflows to pause or delay their execution for a specified period of time.
required: [ wait ]
unevaluatedProperties: false
- properties:
- wait:
- $ref: '#/$defs/duration'
- title: WaitTaskConfiguration
- description: The amount of time to wait.
+ allOf:
+ - $ref: '#/$defs/taskBase'
+ - properties:
+ wait:
+ $ref: '#/$defs/duration'
+ title: WaitTaskConfiguration
+ description: The amount of time to wait.
flowDirective:
title: FlowDirective
description: Represents different transition options for a workflow.
@@ -1188,13 +1214,21 @@ $defs:
title: ExpressionErrorInstance
description: An expression based error instance.
title:
- type: string
- title: ErrorTitle
description: A short, human-readable summary of the error.
+ title: ErrorTitle
+ anyOf:
+ - $ref: '#/$defs/runtimeExpression'
+ title: ExpressionErrorTitle
+ - type: string
+ title: LiteralErrorTitle
detail:
- type: string
title: ErrorDetails
description: A human-readable explanation specific to this occurrence of the error.
+ anyOf:
+ - $ref: '#/$defs/runtimeExpression'
+ title: ExpressionErrorDetails
+ - type: string
+ title: LiteralErrorDetails
required: [ type, status ]
errorFilter:
type: object
diff --git a/custom-generator/pom.xml b/custom-generator/pom.xml
index 3660e286..6313203e 100644
--- a/custom-generator/pom.xml
+++ b/custom-generator/pom.xml
@@ -1,10 +1,9 @@
-
+
4.0.0
io.serverlessworkflow
serverlessworkflow-parent
- 8.0.0-SNAPSHOT
+ 7.1.0.Final
serverless-workflow-custom-generator
Serverless Workflow :: Custom Generator
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 622efcbb..28a611cb 100644
--- a/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java
+++ b/custom-generator/src/main/java/io/serverlessworkflow/generator/AllAnyOneOfSchemaRule.java
@@ -52,6 +52,7 @@
class AllAnyOneOfSchemaRule extends SchemaRule {
+ private static final String ALL_OF = "allOf";
private RuleFactory ruleFactory;
AllAnyOneOfSchemaRule(RuleFactory ruleFactory) {
@@ -142,7 +143,7 @@ public JType apply(
unionType("oneOf", nodeName, schemaNode, parent, generatableType, schema, oneOfTypes);
unionType("anyOf", nodeName, schemaNode, parent, generatableType, schema, oneOfTypes);
- unionType("allOf", nodeName, schemaNode, parent, generatableType, schema, allOfTypes);
+ allOfType(nodeName, schemaNode, parent, generatableType, schema, allOfTypes);
Collections.sort(oneOfTypes);
@@ -204,6 +205,100 @@ public JType apply(
return javaType;
}
+ private void allOfType(
+ String nodeName,
+ JsonNode schemaNode,
+ JsonNode parent,
+ JClassContainer generatableType,
+ Schema schema,
+ List allOfTypes) {
+ if (schemaNode.has(ALL_OF)) {
+ ArrayNode array = (ArrayNode) schemaNode.get(ALL_OF);
+ if (array.size() == 2) {
+ JsonNode refNode = null;
+ JsonNode propsNode = null;
+ int refNodePos = 0;
+ int propsNodePos = 0;
+ int pos = 0;
+ for (JsonNode node : array) {
+ if (node.isObject() && node.size() == 1) {
+ if (node.has(REF)) {
+ refNode = node;
+ refNodePos = pos++;
+ } else if (node.has("properties")) {
+ propsNode = node;
+ propsNodePos = pos++;
+ } else {
+ pos++;
+ break;
+ }
+ }
+ }
+ if (refNode != null && propsNode != null) {
+ allOfTypes.add(
+ new JTypeWrapper(
+ inheritanceNode(
+ nodeName,
+ schemaNode,
+ generatableType,
+ schema,
+ refNode,
+ refNodePos,
+ propsNode,
+ propsNodePos),
+ array));
+ return;
+ }
+ }
+ unionType(ALL_OF, nodeName, schemaNode, parent, generatableType, schema, allOfTypes);
+ }
+ }
+
+ private JType inheritanceNode(
+ String nodeName,
+ JsonNode schemaNode,
+ JClassContainer container,
+ Schema schema,
+ JsonNode refNode,
+ int refNodePos,
+ JsonNode propsNode,
+ int propsNodePos) {
+ try {
+ JDefinedClass javaType =
+ container._class(
+ ruleFactory
+ .getNameHelper()
+ .getUniqueClassName(nodeName, schemaNode, container.getPackage()));
+ javaType._extends(
+ (JClass)
+ refType(
+ refNode.get(REF).asText(),
+ nodeName,
+ refNode,
+ schemaNode,
+ container,
+ childSchema(schema, ALL_OF, refNodePos)));
+ ruleFactory
+ .getPropertiesRule()
+ .apply(
+ nodeName,
+ propsNode.get("properties"),
+ propsNode,
+ javaType,
+ childSchema(schema, ALL_OF, propsNodePos));
+ return javaType;
+ } catch (JClassAlreadyExistsException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private Schema childSchema(Schema parentSchema, String prefix, int pos) {
+ String ref = parentSchema.getId().toString() + '/' + prefix + '/' + pos;
+ return ruleFactory
+ .getSchemaStore()
+ .create(URI.create(ref), ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters());
+ }
+
private JDefinedClass populateAllOf(
Schema parentSchema, JDefinedClass definedClass, Collection allOfTypes) {
return wrapAll(parentSchema, definedClass, Optional.empty(), allOfTypes, Optional.empty());
@@ -344,8 +439,10 @@ private void wrapIt(
Optional valueField,
JType unionType,
JsonNode node) {
- JFieldVar instanceField = getInstanceField(parentSchema, definedClass, unionType, node);
- JMethod method = getSetterMethod(definedClass, instanceField, node);
+ String typeName = getTypeName(node, unionType, parentSchema);
+ JFieldVar instanceField =
+ getInstanceField(typeName, parentSchema, definedClass, unionType, node);
+ JMethod method = getSetterMethod(typeName, definedClass, instanceField, node);
method
.body()
.assign(
@@ -370,8 +467,8 @@ private JVar setupMethod(
}
private JMethod getSetterMethod(
- JDefinedClass definedClass, JFieldVar instanceField, JsonNode node) {
- String setterName = ruleFactory.getNameHelper().getSetterName(instanceField.name(), node);
+ String fieldName, JDefinedClass definedClass, JFieldVar instanceField, JsonNode node) {
+ String setterName = ruleFactory.getNameHelper().getSetterName(fieldName, node);
JMethod fluentMethod =
definedClass.method(JMod.PUBLIC, definedClass, setterName.replaceFirst("set", "with"));
JBlock body = fluentMethod.body();
@@ -391,9 +488,10 @@ private void wrapStrings(
if (pattern == null && iter.hasNext()) {
pattern = ".*";
}
+ String typeName = getTypeName(first.getNode(), first.getType(), parentSchema);
JFieldVar instanceField =
- getInstanceField(parentSchema, definedClass, first.getType(), first.getNode());
- JMethod setterMethod = getSetterMethod(definedClass, instanceField, first.getNode());
+ getInstanceField(typeName, parentSchema, definedClass, first.getType(), first.getNode());
+ JMethod setterMethod = getSetterMethod(typeName, definedClass, instanceField, first.getNode());
JVar methodParam = setupMethod(definedClass, setterMethod, valueField, instanceField);
JBlock body = setterMethod.body();
if (pattern != null) {
@@ -403,7 +501,12 @@ private void wrapStrings(
while (iter.hasNext()) {
JTypeWrapper item = iter.next();
instanceField =
- getInstanceField(parentSchema, definedClass, item.getType(), item.getNode());
+ getInstanceField(
+ getTypeName(item.getNode(), item.getType(), parentSchema),
+ parentSchema,
+ definedClass,
+ item.getType(),
+ item.getNode());
pattern = pattern(item.getNode(), parentSchema);
if (pattern == null) {
pattern = ".*";
@@ -431,16 +534,16 @@ private void wrapStrings(
}
private JFieldVar getInstanceField(
- Schema parentSchema, JDefinedClass definedClass, JType type, JsonNode node) {
+ String fieldName,
+ Schema parentSchema,
+ JDefinedClass definedClass,
+ JType type,
+ JsonNode node) {
JFieldVar instanceField =
definedClass.field(
- JMod.PRIVATE,
- type,
- ruleFactory
- .getNameHelper()
- .getPropertyName(getTypeName(node, type, parentSchema), node));
+ JMod.PRIVATE, type, ruleFactory.getNameHelper().getPropertyName(fieldName, node));
GeneratorUtils.getterMethod(
- definedClass, instanceField, ruleFactory.getNameHelper(), instanceField.name());
+ definedClass, instanceField, ruleFactory.getNameHelper(), fieldName);
return instanceField;
}
@@ -486,13 +589,7 @@ private void unionType(
int i = 0;
for (JsonNode oneOf : array) {
if (!ignoreNode(oneOf)) {
- String ref = parentSchema.getId().toString() + '/' + prefix + '/' + i++;
- Schema schema =
- ruleFactory
- .getSchemaStore()
- .create(
- URI.create(ref),
- ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters());
+ Schema schema = childSchema(parentSchema, prefix, i++);
types.add(
new JTypeWrapper(
schema.isGenerated()
@@ -529,29 +626,39 @@ private Optional refType(
String nodeName,
JsonNode schemaNode,
JsonNode parent,
- JClassContainer generatableType,
+ JClassContainer container,
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, schemaNode),
- schema.getContent(),
- parent,
- generatableType,
- schema));
- }
- return Optional.empty();
+ return schemaNode.has(REF)
+ ? Optional.of(
+ refType(
+ schemaNode.get(REF).asText(),
+ nodeName,
+ schemaNode,
+ parent,
+ container,
+ parentSchema))
+ : Optional.empty();
+ }
+
+ private JType refType(
+ String ref,
+ String nodeName,
+ JsonNode schemaNode,
+ JsonNode parent,
+ JClassContainer container,
+ Schema parentSchema) {
+ Schema schema =
+ ruleFactory
+ .getSchemaStore()
+ .create(
+ parentSchema,
+ ref,
+ ruleFactory.getGenerationConfig().getRefFragmentPathDelimiters());
+
+ return schema.isGenerated()
+ ? schema.getJavaType()
+ : apply(
+ nameFromRef(ref, nodeName, schemaNode), schema.getContent(), parent, container, schema);
}
private JsonNode schemaRef(JsonNode schemaNode, Schema parentSchema) {
diff --git a/impl/core/pom.xml b/impl/core/pom.xml
index a5fac29a..e8f808b1 100644
--- a/impl/core/pom.xml
+++ b/impl/core/pom.xml
@@ -1,10 +1,9 @@
-
+
4.0.0
io.serverlessworkflow
serverlessworkflow-impl
- 8.0.0-SNAPSHOT
+ 7.1.0.Final
serverlessworkflow-impl-core
Serverless Workflow :: Impl :: Core
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/AbstractTaskExecutor.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/AbstractTaskExecutor.java
index f51b7a01..23ca9a22 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/AbstractTaskExecutor.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/AbstractTaskExecutor.java
@@ -49,12 +49,14 @@ public abstract class AbstractTaskExecutor implements TaskEx
private final Optional inputSchemaValidator;
private final Optional outputSchemaValidator;
private final Optional contextSchemaValidator;
+ private final Optional ifFilter;
public abstract static class AbstractTaskExecutorBuilder
implements TaskExecutorBuilder {
private Optional inputProcessor = Optional.empty();
private Optional outputProcessor = Optional.empty();
private Optional contextProcessor = Optional.empty();
+ private Optional ifFilter = Optional.empty();
private Optional inputSchemaValidator = Optional.empty();
private Optional outputSchemaValidator = Optional.empty();
private Optional contextSchemaValidator = Optional.empty();
@@ -100,6 +102,7 @@ protected AbstractTaskExecutorBuilder(
this.contextSchemaValidator =
getSchemaValidator(application.validatorFactory(), resourceLoader, export.getSchema());
}
+ this.ifFilter = optionalFilter(application.expressionFactory(), task.getIf());
}
protected final TransitionInfoBuilder next(
@@ -153,6 +156,7 @@ protected AbstractTaskExecutor(AbstractTaskExecutorBuilder builder) {
this.inputSchemaValidator = builder.inputSchemaValidator;
this.outputSchemaValidator = builder.outputSchemaValidator;
this.contextSchemaValidator = builder.contextSchemaValidator;
+ this.ifFilter = builder.ifFilter;
}
protected final CompletableFuture executeNext(
@@ -177,40 +181,49 @@ public CompletableFuture apply(
if (!TaskExecutorHelper.isActive(workflowContext)) {
return completable;
}
- return executeNext(
- completable
- .thenApply(
- t -> {
- workflowContext
- .definition()
- .listeners()
- .forEach(l -> l.onTaskStarted(position, task));
- inputSchemaValidator.ifPresent(s -> s.validate(t.rawInput()));
- inputProcessor.ifPresent(
- p -> taskContext.input(p.apply(workflowContext, t, t.rawInput())));
- return t;
- })
- .thenCompose(t -> execute(workflowContext, t))
- .thenApply(
- t -> {
- outputProcessor.ifPresent(
- p -> t.output(p.apply(workflowContext, t, t.rawOutput())));
- outputSchemaValidator.ifPresent(s -> s.validate(t.output()));
- contextProcessor.ifPresent(
- p ->
- workflowContext.context(
- p.apply(workflowContext, t, workflowContext.context())));
- contextSchemaValidator.ifPresent(s -> s.validate(workflowContext.context()));
- t.completedAt(Instant.now());
- workflowContext
- .definition()
- .listeners()
- .forEach(l -> l.onTaskEnded(position, task));
- return t;
- }),
- workflowContext);
+ if (ifFilter
+ .map(f -> f.apply(workflowContext, taskContext, input).asBoolean(true))
+ .orElse(true)) {
+ return executeNext(
+ completable
+ .thenApply(
+ t -> {
+ workflowContext
+ .definition()
+ .listeners()
+ .forEach(l -> l.onTaskStarted(position, task));
+ inputSchemaValidator.ifPresent(s -> s.validate(t.rawInput()));
+ inputProcessor.ifPresent(
+ p -> taskContext.input(p.apply(workflowContext, t, t.rawInput())));
+ return t;
+ })
+ .thenCompose(t -> execute(workflowContext, t))
+ .thenApply(
+ t -> {
+ outputProcessor.ifPresent(
+ p -> t.output(p.apply(workflowContext, t, t.rawOutput())));
+ outputSchemaValidator.ifPresent(s -> s.validate(t.output()));
+ contextProcessor.ifPresent(
+ p ->
+ workflowContext.context(
+ p.apply(workflowContext, t, workflowContext.context())));
+ contextSchemaValidator.ifPresent(s -> s.validate(workflowContext.context()));
+ t.completedAt(Instant.now());
+ workflowContext
+ .definition()
+ .listeners()
+ .forEach(l -> l.onTaskEnded(position, task));
+ return t;
+ }),
+ workflowContext);
+ } else {
+ taskContext.transition(getSkipTransition());
+ return executeNext(completable, workflowContext);
+ }
}
+ protected abstract TransitionInfo getSkipTransition();
+
protected abstract CompletableFuture execute(
WorkflowContext workflow, TaskContext taskContext);
}
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RaiseExecutor.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RaiseExecutor.java
index 6dd43c2b..7a2c4025 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RaiseExecutor.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RaiseExecutor.java
@@ -30,7 +30,6 @@
import io.serverlessworkflow.impl.WorkflowException;
import io.serverlessworkflow.impl.WorkflowPosition;
import io.serverlessworkflow.impl.WorkflowUtils;
-import io.serverlessworkflow.impl.executors.RegularTaskExecutor.RegularTaskExecutorBuilder;
import io.serverlessworkflow.impl.expressions.ExpressionFactory;
import io.serverlessworkflow.impl.resources.ResourceLoader;
import java.util.Map;
@@ -66,9 +65,15 @@ protected RaiseExecutorBuilder(
this.instanceFilter =
getInstanceFunction(application.expressionFactory(), error.getInstance());
this.titleFilter =
- WorkflowUtils.buildStringFilter(application.expressionFactory(), error.getTitle());
+ WorkflowUtils.buildStringFilter(
+ application.expressionFactory(),
+ error.getTitle().getExpressionErrorTitle(),
+ error.getTitle().getLiteralErrorTitle());
this.detailFilter =
- WorkflowUtils.buildStringFilter(application.expressionFactory(), error.getDetail());
+ WorkflowUtils.buildStringFilter(
+ application.expressionFactory(),
+ error.getDetail().getExpressionErrorDetails(),
+ error.getTitle().getExpressionErrorTitle());
this.errorBuilder = (w, t) -> buildError(error, w, t);
}
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RegularTaskExecutor.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RegularTaskExecutor.java
index 24c1e841..7cac9a8e 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RegularTaskExecutor.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/RegularTaskExecutor.java
@@ -54,6 +54,11 @@ public void connect(Map> connections) {
}
}
+ @Override
+ protected TransitionInfo getSkipTransition() {
+ return transition;
+ }
+
protected CompletableFuture execute(
WorkflowContext workflow, TaskContext taskContext) {
CompletableFuture future =
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/SetExecutor.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/SetExecutor.java
index c5600891..f8373d39 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/SetExecutor.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/SetExecutor.java
@@ -16,25 +16,26 @@
package io.serverlessworkflow.impl.executors;
import com.fasterxml.jackson.databind.JsonNode;
+import io.serverlessworkflow.api.types.Set;
import io.serverlessworkflow.api.types.SetTask;
+import io.serverlessworkflow.api.types.SetTaskConfiguration;
import io.serverlessworkflow.api.types.Workflow;
import io.serverlessworkflow.impl.TaskContext;
import io.serverlessworkflow.impl.WorkflowApplication;
import io.serverlessworkflow.impl.WorkflowContext;
+import io.serverlessworkflow.impl.WorkflowFilter;
import io.serverlessworkflow.impl.WorkflowPosition;
-import io.serverlessworkflow.impl.expressions.ExpressionUtils;
-import io.serverlessworkflow.impl.json.JsonUtils;
+import io.serverlessworkflow.impl.WorkflowUtils;
import io.serverlessworkflow.impl.resources.ResourceLoader;
-import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class SetExecutor extends RegularTaskExecutor {
- private final Map toBeSet;
+ private final WorkflowFilter setFilter;
public static class SetExecutorBuilder extends RegularTaskExecutorBuilder {
- private final Map toBeSet;
+ private final WorkflowFilter setFilter;
protected SetExecutorBuilder(
WorkflowPosition position,
@@ -43,9 +44,13 @@ protected SetExecutorBuilder(
WorkflowApplication application,
ResourceLoader resourceLoader) {
super(position, task, workflow, application, resourceLoader);
- this.toBeSet =
- ExpressionUtils.buildExpressionMap(
- task.getSet().getAdditionalProperties(), application.expressionFactory());
+ Set setInfo = task.getSet();
+ SetTaskConfiguration setConfig = setInfo.getSetTaskConfiguration();
+ this.setFilter =
+ WorkflowUtils.buildWorkflowFilter(
+ application.expressionFactory(),
+ setInfo.getString(),
+ setConfig != null ? setConfig.getAdditionalProperties() : null);
}
@Override
@@ -56,15 +61,13 @@ public TaskExecutor buildInstance() {
private SetExecutor(SetExecutorBuilder builder) {
super(builder);
- this.toBeSet = builder.toBeSet;
+ this.setFilter = builder.setFilter;
}
@Override
protected CompletableFuture internalExecute(
WorkflowContext workflow, TaskContext taskContext) {
return CompletableFuture.completedFuture(
- JsonUtils.fromValue(
- ExpressionUtils.evaluateExpressionMap(
- toBeSet, workflow, taskContext, taskContext.input())));
+ setFilter.apply(workflow, taskContext, taskContext.input()));
}
}
diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/SwitchExecutor.java b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/SwitchExecutor.java
index 70b127c4..9bd3a74a 100644
--- a/impl/core/src/main/java/io/serverlessworkflow/impl/executors/SwitchExecutor.java
+++ b/impl/core/src/main/java/io/serverlessworkflow/impl/executors/SwitchExecutor.java
@@ -79,6 +79,11 @@ protected TaskExecutor buildInstance() {
}
}
+ @Override
+ protected TransitionInfo getSkipTransition() {
+ return defaultTask;
+ }
+
private SwitchExecutor(SwitchExecutorBuilder builder) {
super(builder);
this.defaultTask = TransitionInfo.build(builder.defaultTask);
diff --git a/impl/core/src/test/java/io/serverlessworkflow/impl/WorkflowDefinitionTest.java b/impl/core/src/test/java/io/serverlessworkflow/impl/WorkflowDefinitionTest.java
index 4ea87283..4a0a073f 100644
--- a/impl/core/src/test/java/io/serverlessworkflow/impl/WorkflowDefinitionTest.java
+++ b/impl/core/src/test/java/io/serverlessworkflow/impl/WorkflowDefinitionTest.java
@@ -81,6 +81,14 @@ private static Stream provideParameters() {
"simple-expression.yaml",
Map.of("input", Arrays.asList(1, 2, 3)),
WorkflowDefinitionTest::checkSpecialKeywords),
+ args(
+ "conditional-set.yaml",
+ Map.of("enabled", true),
+ WorkflowDefinitionTest::checkEnableCondition),
+ args(
+ "conditional-set.yaml",
+ Map.of("enabled", false),
+ WorkflowDefinitionTest::checkDisableCondition),
args(
"raise-inline copy.yaml",
WorkflowDefinitionTest::checkWorkflowException,
@@ -166,4 +174,14 @@ private static void checkSpecialKeywords(Object obj) {
assertThat(result.get("id").toString()).hasSize(26);
assertThat(result.get("version").toString()).contains("alpha");
}
+
+ private static void checkEnableCondition(Object obj) {
+ Map result = (Map) obj;
+ assertThat(result.get("name")).isEqualTo("javierito");
+ }
+
+ private static void checkDisableCondition(Object obj) {
+ Map result = (Map) obj;
+ assertThat(result.get("enabled")).isEqualTo(false);
+ }
}
diff --git a/impl/core/src/test/resources/conditional-set.yaml b/impl/core/src/test/resources/conditional-set.yaml
new file mode 100644
index 00000000..5e06622d
--- /dev/null
+++ b/impl/core/src/test/resources/conditional-set.yaml
@@ -0,0 +1,10 @@
+document:
+ dsl: '1.0.0-alpha5'
+ namespace: test
+ name: conditional-set
+ version: '0.1.0'
+do:
+ - conditionalExpression:
+ if: .enabled
+ set:
+ name: javierito
\ No newline at end of file
diff --git a/impl/http/pom.xml b/impl/http/pom.xml
index fdf2a168..14e7126e 100644
--- a/impl/http/pom.xml
+++ b/impl/http/pom.xml
@@ -1,10 +1,9 @@
-
+
4.0.0
io.serverlessworkflow
serverlessworkflow-impl
- 8.0.0-SNAPSHOT
+ 7.1.0.Final
serverlessworkflow-impl-http
Serverless Workflow :: Impl :: HTTP
@@ -41,5 +40,10 @@
assertj-core
test
+
+ ch.qos.logback
+ logback-classic
+ test
+
\ No newline at end of file
diff --git a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/HttpExecutor.java b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/HttpExecutor.java
index 3c078309..d60c4655 100644
--- a/impl/http/src/main/java/io/serverlessworkflow/impl/executors/HttpExecutor.java
+++ b/impl/http/src/main/java/io/serverlessworkflow/impl/executors/HttpExecutor.java
@@ -28,6 +28,8 @@
import io.serverlessworkflow.impl.WorkflowContext;
import io.serverlessworkflow.impl.WorkflowError;
import io.serverlessworkflow.impl.WorkflowException;
+import io.serverlessworkflow.impl.WorkflowFilter;
+import io.serverlessworkflow.impl.WorkflowUtils;
import io.serverlessworkflow.impl.expressions.Expression;
import io.serverlessworkflow.impl.expressions.ExpressionFactory;
import io.serverlessworkflow.impl.expressions.ExpressionUtils;
@@ -40,8 +42,10 @@
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.Invocation.Builder;
import jakarta.ws.rs.client.WebTarget;
+import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Optional;
import java.util.concurrent.CompletableFuture;
public class HttpExecutor implements CallableTask {
@@ -49,8 +53,8 @@ public class HttpExecutor implements CallableTask {
private static final Client client = ClientBuilder.newClient();
private TargetSupplier targetSupplier;
- private Map headersMap;
- private Map queryMap;
+ private Optional headersMap;
+ private Optional queryMap;
private RequestSupplier requestFunction;
@FunctionalInterface
@@ -70,14 +74,24 @@ public void init(CallHTTP task, WorkflowApplication application, ResourceLoader
getTargetSupplier(httpArgs.getEndpoint(), application.expressionFactory());
this.headersMap =
httpArgs.getHeaders() != null
- ? ExpressionUtils.buildExpressionMap(
- httpArgs.getHeaders().getAdditionalProperties(), application.expressionFactory())
- : Map.of();
+ ? Optional.of(
+ WorkflowUtils.buildWorkflowFilter(
+ application.expressionFactory(),
+ httpArgs.getHeaders().getRuntimeExpression(),
+ httpArgs.getHeaders().getHTTPHeaders() != null
+ ? httpArgs.getHeaders().getHTTPHeaders().getAdditionalProperties()
+ : null))
+ : Optional.empty();
this.queryMap =
httpArgs.getQuery() != null
- ? ExpressionUtils.buildExpressionMap(
- httpArgs.getQuery().getAdditionalProperties(), application.expressionFactory())
- : Map.of();
+ ? Optional.of(
+ WorkflowUtils.buildWorkflowFilter(
+ application.expressionFactory(),
+ httpArgs.getQuery().getRuntimeExpression(),
+ httpArgs.getQuery().getHTTPQuery() != null
+ ? httpArgs.getQuery().getHTTPQuery().getAdditionalProperties()
+ : null))
+ : Optional.empty();
switch (httpArgs.getMethod().toUpperCase()) {
case HttpMethod.POST:
Object body =
@@ -100,13 +114,22 @@ public void init(CallHTTP task, WorkflowApplication application, ResourceLoader
public CompletableFuture apply(
WorkflowContext workflow, TaskContext taskContext, JsonNode input) {
WebTarget target = targetSupplier.apply(workflow, taskContext, input);
- for (Entry entry :
- ExpressionUtils.evaluateExpressionMap(queryMap, workflow, taskContext, input).entrySet()) {
- target = target.queryParam(entry.getKey(), entry.getValue());
+ Optional queryJson = queryMap.map(q -> q.apply(workflow, taskContext, input));
+ if (queryJson.isPresent()) {
+ Iterator> iter = queryJson.orElseThrow().fields();
+ while (iter.hasNext()) {
+ Entry item = iter.next();
+ target = target.queryParam(item.getKey(), JsonUtils.toJavaValue(item.getValue()));
+ }
}
+
Builder request = target.request();
- ExpressionUtils.evaluateExpressionMap(headersMap, workflow, taskContext, input)
- .forEach(request::header);
+ headersMap.ifPresent(
+ h ->
+ h.apply(workflow, taskContext, input)
+ .fields()
+ .forEachRemaining(
+ e -> request.header(e.getKey(), JsonUtils.toJavaValue(e.getValue()))));
return CompletableFuture.supplyAsync(
() -> {
try {
diff --git a/impl/http/src/test/java/io/serverlessworkflow/impl/HTTPWorkflowDefinitionTest.java b/impl/http/src/test/java/io/serverlessworkflow/impl/HTTPWorkflowDefinitionTest.java
index 7492be53..badb6403 100644
--- a/impl/http/src/test/java/io/serverlessworkflow/impl/HTTPWorkflowDefinitionTest.java
+++ b/impl/http/src/test/java/io/serverlessworkflow/impl/HTTPWorkflowDefinitionTest.java
@@ -98,7 +98,7 @@ private static Stream provideParameters() {
"call-http-query-parameters-external-schema.yaml", starTrekInput, starTrekCondition),
Arguments.of(
"callPostHttp.yaml",
- Map.of("name", "Javierito", "status", "available"),
+ Map.of("name", "Javierito", "surname", "Unknown"),
new Condition<>(o -> o.equals("Javierito"), "CallHttpPostCondition")));
}
}
diff --git a/impl/http/src/test/resources/callPostHttp.yaml b/impl/http/src/test/resources/callPostHttp.yaml
index d66dcfaa..f12fec42 100644
--- a/impl/http/src/test/resources/callPostHttp.yaml
+++ b/impl/http/src/test/resources/callPostHttp.yaml
@@ -9,20 +9,9 @@ do:
with:
method: post
endpoint:
- uri: https://petstore.swagger.io/v2/pet
+ uri: https://fakerestapi.azurewebsites.net/api/v1/Authors
body:
- name: ${.name}
- status: ${.status}
+ firstName: ${.name}
+ lastName: ${.surname }
output:
- as: .id
- - getPet:
- call: http
- with:
- method: get
- endpoint:
- uri: https://petstore.swagger.io/v2/pet/{petId}
- input:
- from:
- petId: ${.}
- output:
- as: .name
\ No newline at end of file
+ as: .firstName
\ No newline at end of file
diff --git a/impl/pom.xml b/impl/pom.xml
index 65fa9095..a8297955 100644
--- a/impl/pom.xml
+++ b/impl/pom.xml
@@ -1,10 +1,9 @@
-
+
4.0.0
io.serverlessworkflow
serverlessworkflow-parent
- 8.0.0-SNAPSHOT
+ 7.1.0.Final
serverlessworkflow-impl
Serverless Workflow :: Impl
diff --git a/pom.xml b/pom.xml
index e054f843..54ef626d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,11 +1,10 @@
-
+
4.0.0
io.serverlessworkflow
serverlessworkflow-parent
- 8.0.0-SNAPSHOT
+ 7.1.0.Final
pom
Serverless Workflow :: Parent
@@ -34,7 +33,7 @@
scm:git:git@github.com:serverlessworkflow/sdk-java.git
scm:git:git@github.com:serverlessworkflow/sdk-java.git
https://github.com/serverlessworkflow/sdk-java
- HEAD
+ 7.1.0.Final
@@ -53,10 +52,10 @@
3.2.1
3.6.0
- 3.13.0
- 3.1.3
+ 3.14.0
+ 3.1.4
3.5.0
- 3.5.2
+ 3.5.3
2.25
3.2.7
3.4.2
@@ -65,20 +64,20 @@
3.11.2
3.1.1
3.3.1
- 3.5.2
- 1.6.13
+ 3.5.3
+ 1.7.0
- 1.5.16
- 2.18.2
- 1.5.5
+ 1.5.18
+ 2.18.3
+ 1.5.6
3.1.1
1.5.2
3.27.3
- 5.11.4
- 5.15.2
- 2.0.16
+ 5.12.2
+ 5.17.0
+ 2.0.17
8.0.2.Final
5.0.0
@@ -241,13 +240,13 @@
-
-
+
+
-
-
+
+