//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.
//
=== Workflow

Workflow manages the internal identity lifecycle by defining statuses and transitions that every user, group or any
object in Apache Syncope will traverse. A workflow instance is started once identities get created, and shut down when
they are removed.

Workflow is triggered during the <<provisioning,provisioning>> process as the first step in creating, updating or deleting
identities into the internal storage.

[[workflow-adapters]]
[NOTE]
.Workflow Adapters
====
The workflow features are defined by the workflow adapter interfaces:

ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java[UserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/blob/4_0_X/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java[UserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/GroupWorkflowAdapter.java[GroupWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/blob/4_0_X/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/GroupWorkflowAdapter.java[GroupWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/AnyObjectWorkflowAdapter.java[AnyObjectWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/blob/4_0_X/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/AnyObjectWorkflowAdapter.java[AnyObjectWorkflowAdapter^]
endif::[]

Default implementations are available:

ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/blob/4_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java[DefaultGroupWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/blob/4_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java[DefaultGroupWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "release"]
* https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java[DefaultAnyObjectWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
* https://github.com/apache/syncope/blob/4_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java[DefaultAnyObjectWorkflowAdapter^]
endif::[]

Custom adapters can be provided by implementing the related interfaces, also as bridges towards third-party tools as 
https://camunda.org/[Camunda^] or http://jbpm.jboss.org/[jBPM^].
====

[[which-user-worflow-adapter]]
[TIP]
.Which workflow adapter for users?
====
. Do you need <<approval,approval>> management? <<flowable-user-workflow-adapter,Flowable>>
. If approval management is not needed, do you want to customize the internal user processing, or attach custom logic
to it? Provide a Java class with your customizations, extending
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/4_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
. No approval nor customizations needed? Stick with
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/tree/4_0_X/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java[DefaultUserWorkflowAdapter^]
endif::[]
====

==== Flowable User Workflow Adapter

An advanced adapter is provided for Users, based on https://www.flowable.org/[Flowable^], one of reference open
source http://www.bpmn.org/[BPMN 2.0^] implementations.

The
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/impl/FlowableUserWorkflowAdapter.java[FlowableUserWorkflowAdapter^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_0_X/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/impl/FlowableUserWorkflowAdapter.java[FlowableUserWorkflowAdapter^]
endif::[]
is bootstrapped from
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/ext/flowable/flowable-bpmn/src/main/resources/userWorkflow.bpmn20.xml[userWorkflow.bpmn20.xml^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_0_X/ext/flowable/flowable-bpmn/src/main/resources/userWorkflow.bpmn20.xml[userWorkflow.bpmn20.xml^]
endif::[]
and presents several advantages and more features, if compared to the default user adapter:

. Besides mandatory statuses, which are modeled as BPMN `userTask` instances, more can be freely added
at runtime, provided that adequate transitions and conditions are also inserted; more details about available BPMN
constructs are available in the https://www.flowable.com/open-source/docs/bpmn/ch07b-BPMN-Constructs[Flowable User Guide^]. +
Additional statuses and transitions allow the internal processes of Apache Syncope to better adapt to suit organizational flows.
. Custom logic can be injected into the workflow process by providing BPMN `serviceTask` instances.
. Flowable forms are used for implementing <<approval,approval>>.
. <<admin-console,admin console>> supports web-based graphical modeling of the workflow definition.

[.text-center]
image::userWorkflow.png[title="Default Flowable user workflow",alt="Default Flowable user workflow"] 

===== Approval

Every transition in the Flowable user workflow definition can be subjected to approval.

The underlying idea is that some kind of self-modifications (group memberships, external resource assignments, ...)
might not be allowed to 'plain' Users, as there could be conditions which require management approval.
Managers could also be asked to complete the information provided before the requested operation is finished.

In order to define an approval form, a dedicated BPMN `userTask` needs to be defined, following the rules established
for Flowable forms.

[NOTE]
.What is required for administrators to manage approval?
====
The following conditions must be met, for an User `U` to act as administrator for approval:

. `U` must own the following <<entitlements,entitlements>>, for all the required realms:
.. `USER_REQUEST_FORM_CLAIM`
.. `USER_REQUEST_FORM_LIST`
.. `USER_REQUEST_FORM_SUBMIT`
.. `USER_READ`
. The BPMN `userTask` must either indicate `U` among `candidateUsers` or at least one of the groups assigned to `U`
among `candidateGroups`, as required by
https://www.flowable.com/open-source/docs/bpmn/ch07b-BPMN-Constructs#flowable-extensions-for-task-assignment[Flowable's task assignment rules^]

The special super-user `admin` is entitled to manage all approvals, even those not specifying any
`candidateUsers` or `candidateGroups`.
====

[[sample-selfreg-approval]]
.Approving self-registration
====
The snippet below shows how to define an approval form in XML; the same operation can be performed via the GUI editor
provided by <<admin-console,admin console>>.

[source,xml]
----
<userTask id="createApproval" name="Create approval"
          flowable:candidateGroups="managingDirector"
          flowable:formKey="createApproval"> // <1>
  <extensionElements>
    <flowable:formProperty id="username" name="Username" type="string"
                           expression="${userTO.username}" writable="false"/> // <2>
    <flowable:formProperty id="approve" name="Approve?" type="boolean"
                           variable="approve" required="true"/> // <3>
    <flowable:formProperty id="rejectReason" name="Reason for rejecting" type="string"
                           variable="rejectReason"/>
  </extensionElements>
</userTask>
----
<1> `formKey` and `id` must be unique across the workflow definition, `name` is displayed by the admin console;
`candidateGroups` and `candidateUsers` might be defined, even both, to indicate which Groups or Users should be
managing these approvals; if none are specified, only `admin` is entitled to manage such approval
<2> `expression` will be evaluated against the current requesting `user` (as workflow variable) and related properties;
read-only form input can be defined by setting `writable="false"`
<3> exporting approval inputs into workflow variables is possible via the `variable` attribute; required form input can
be defined by setting `required="true"`
====

Once the form is defined, any modification subject to that approval will be manageable via the admin console, according to
the following flow (the actual operations on the admin console for the sample above are reported <<console-approval,below>>):

. administrator A sees the new approval notifications +
. administrator A claims the approval and is then allowed to manage it
. administrator A reviews the updated user, with ongoing modification applied (no actual modification performed yet)
. administrator A can approve or reject such modification

===== Request Management

Request management is a key-feature of Identity Governance and allows to define and manage, in a structured way,
whatever process intended to update identity attributes, memberships and relationships. +
Request examples are "assign mobile phone", "grant groups on AD" or "consent access to application".

Users can initiate whichever request among the ones defined; once initiated, such requests will follow their own path,
which might also include one or more <<approval,approval>> steps.

[[sample-user-request]]
.Assigning printer to user
====
The BPMN process below shows how to define an user request in XML; the same operation can be performed via the GUI
editor provided by <<admin-console,admin console>>.

In this user request definition:

. user selects one of printers defined in the system, for self-assignment
. administrator approves user's selection
. a <<memberships-relationships,relationship>> between user and printer is established

[source,xml]
----
<process id="assignPrinterRequest" name="Assign printer" isExecutable="true">
  <startEvent id="startevent1" name="Start"/>
  <endEvent id="endevent1" name="End"/>
  <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="selectPrinter"/>
  <userTask id="selectPrinter" name="Select printer" flowable:formKey="selectPrinter"
            flowable:assignee="${wfExecutor}"> // <1>
    <extensionElements>
      <flowable:formProperty id="printer" name="Printer"
                             variable="printer" type="dropdown" required="true"> // <2>
        <flowable:value id="dropdownValueProvider" name="printersValueProvider"/>
      </flowable:formProperty>
      <flowable:formProperty id="printMode" name="Preferred print mode?" type="enum">
        <flowable:value id="bw" name="Black / White"/>
        <flowable:value id="color" name="Color"/>
      </flowable:formProperty>
    </extensionElements>
  </userTask>
  <userTask id="approvePrinter" name="Approve printer" flowable:formKey="approvePrinter"> // <3>
    <extensionElements>
      <flowable:formProperty id="username" name="Username" type="string" 
                             expression="${userTO.username}" writable="false"/>
      <flowable:formProperty id="printer" name="Selected printer" type="string" 
                             expression="${printer}" writable="false"/>
      <flowable:formProperty id="approve" name="Approve?" type="boolean"
                             variable="approve" required="true"/>
    </extensionElements>
  </userTask>
  <sequenceFlow id="sid-D7047714-8E57-46B8-B6D4-4844DE330329"
                sourceRef="selectPrinter" targetRef="approvePrinter"/>
  <serviceTask id="createARelationship" name="Create ARelationship"
               flowable:delegateExpression="${createARelationship}"/> // <4>
  <sequenceFlow id="sid-33880AE7-35C6-4A39-8E5B-12D8BA53F042"
                sourceRef="approvePrinter" targetRef="createARelationship"/>
  <sequenceFlow id="sid-831E1896-EDF9-4F7D-AA42-E86CC1F8C5D3"
                sourceRef="createARelationship" targetRef="endevent1"/>
</process>
----
<1> the first form defined is self-assigned to the user which has started this request
<2> the `dropdown` type is a Syncope extension of the form property types supported by Flowable
and allows to inject a list of elements via the `dropdownValueProvider` value (with name `printersValueProvider` in this
sample), which must be a Spring bean implementing the
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/api/DropdownValueProvider.java[DropdownValueProvider^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_0_X/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/api/DropdownValueProvider.java[DropdownValueProvider^]
endif::[]
interface
<3> the second form is a traditional approval form, as seen <<sample-selfreg-approval,above>>
<4> this is a
ifeval::["{snapshotOrRelease}" == "release"]
https://github.com/apache/syncope/blob/syncope-{docVersion}/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/task/FlowableServiceTask.java[FlowableServiceTask^]
endif::[]
ifeval::["{snapshotOrRelease}" == "snapshot"]
https://github.com/apache/syncope/blob/4_0_X/ext/flowable/flowable-bpmn/src/main/java/org/apache/syncope/core/flowable/task/FlowableServiceTask.java[FlowableServiceTask^]
endif::[]
implementation which takes care of establishing the relationship
====
