Workflow model
The workflow offers three types of steps: 'library' or 'specific' and 'script'.
'Library' is a bean defined in
module.xml and is reusable. Using the 'library' bean improves the ergonomics: parameters are dynamically displayed in the definition screens.
A 'specific' object is a bean defined only by its class name. In this case, the display is not dynamic.
A 'script' is a procedural language based on DSL (Domain Specific Language) used to define custom tasks. The EBX script IDE is used to create and edit the script. The parameters of the workflow context are dynamically displayed in the definition screens.
Related information
Bean categories
| Step | Library | Specific |
|---|---|---|
| Scripts | ScriptTaskBean | ScriptTask |
| Conditions | ConditionBean | Condition |
| User task | UserTask |
Sample of ScriptTask
Java Code
A script task has to override the method
execute as in the following example:
public class NppScriptTask_CreateWorkingBranch extends ScriptTask
{
public void executeScript(ScriptTaskContext aContext) throws OperationException
{
Repository repository = aContext.getRepository();
String initialBranchString = aContext.getVariableString("initialBranch");
AdaptationHome initialBranch = repository.lookupHome(HomeKey.forBranchName(initialBranchString));
if (initialBranch == null)
throw OperationException.createError("Null value for initialBranch");
HomeCreationSpec spec = new HomeCreationSpec();
spec.setParent(initialBranch);
spec.setKey(HomeKey.forBranchName("Name"));
spec.setOwner(Profile.EVERYONE);
spec.setHomeToCopyPermissionsFrom(initialBranch);
AdaptationHome newHome = repository.createHome(spec, aContext.getSession());
//feeds dataContext
aContext.setVariableString("workingBranch", newHome.getKey().getName());
}
}
See also:
Sample of ScriptTaskBean
Java Code
A script task bean has to override the method
executeScript as in the following example:
public class ScriptTaskBean_CreateBranch extends ScriptTaskBean
{
private String initialBranchName;
private String newBranch;
public String getInitialBranchName()
{
return this.initialBranchName;
}
public void setInitialBranchName(String initialBranchName)
{
this.initialBranchName = initialBranchName;
}
public String getNewBranch()
{
return this.newBranch;
}
public void setNewBranch(String newBranch)
{
this.newBranch = newBranch;
}
public void executeScript(ScriptTaskBeanContext aContext) throws OperationException
{
final Repository repository = aContext.getRepository();
String initialBranchName = this.getInitialBranchName();
final AdaptationHome initialBranch = repository.lookupHome(HomeKey.forBranchName(initialBranchName));
final HomeCreationSpec spec = new HomeCreationSpec();
spec.setParent(initialBranch);
spec.setKey(HomeKey.forBranchName(XsFormats.SINGLETON.formatDateTime(new Date())));
spec.setOwner(Profile.EVERYONE);
spec.setHomeToCopyPermissionsFrom(initialBranch);
final AdaptationHome branchCreate = repository.createHome(spec, aContext.getSession());
this.setNewBranch(branchCreate.getKey().getName());
}
}
See also:
Configuration through module.xml
A script task bean must be declared in
module.xml:
<module>
<beans>
<bean className="com.orchestranetworks.workflow.genericScriptTask.ScriptTaskBean_CreateBranch">
<documentation xml:lang="fr-FR">
<label>Créer une branche</label>
<description>
Ce script permet de créer une branche
</description>
</documentation>
<documentation xml:lang="en-US">
<label>Create a branch</label>
<description>
This script creates a branch
</description>
</documentation>
<properties>
<property name="initialBranchName" input="true">
<documentation xml:lang="fr-FR">
<label>Branche initiale</label>
<description>
Nom de la branche initiale.
</description>
</documentation>
<documentation xml:lang="en-US">
<label>Initial branch</label>
<description>
Initial branch name.
</description>
</documentation>
</property>
<property name="newBranch" output="true">
<documentation xml:lang="fr-FR">
<label>Nouvelle branche</label>
<description>
Nom de la branche créée
</description>
</documentation>
<documentation xml:lang="en-US">
<label>New branch</label>
<description>
Created branch name.
</description>
</documentation>
</property>
</properties>
</bean>
</beans>
</module>
Samples of UserTask
Service declaration via module.xml
A built-in service can be declared in
module.xml to be used in the user task definition.
<services>
<service name="ServiceModule">
<resourcePath>/service.jsp</resourcePath>
<type>branch</type>
<documentation xml:lang="fr-FR">
<label>Workflow service</label>
<description>
Ce service permet de ...
</description>
</documentation>
<documentation xml:lang="en-US">
<label>Service workflow</label>
<description>
The purpose of this service is ...
</description>
</documentation>
<properties>
<property name="param1" input="true">
<documentation xml:lang="fr-FR">
<label>Param1</label>
<description>Param1 ...</description>
</documentation>
</property>
<property name="param2" output="true">
</property>
</properties>
</service>
<serviceLink serviceName="adaptationService">
<importFromSchema>
/WEB-INF/ebx/schema/schema.xsd
</importFromSchema>
</serviceLink>
</services>
A more complex UserTask
The GUI is quite similar as the example above. The field 'Rule' must be filled to define the class extending the 'UserTask' to invoke.
public class NppUserTask_ValidateProduct extends UserTask
{
public void handleWorkItemCompletion(UserTaskWorkItemCompletionContext context)
throws OperationException
{
if (context.getCompletedWorkItem().isRejected())
{
context.setVariableString(NppConstants.VAR_VALIDATION, "KO");
context.completeUserTask();
}
else if (context.checkAllWorkItemMatchStrategy())
{
context.setVariableString(NppConstants.VAR_VALIDATION, "OK");
context.completeUserTask();
}
}
public void handleCreate(UserTaskCreationContext context) throws OperationException
{
CreationWorkItemSpec spec = CreationWorkItemSpec.forOfferring(NppConstants.ROLE_PVALIDATOR);
spec.setNotificationMail("1");
context.createWorkItem(spec);
context.setVariableString(NppConstants.VAR_VALIDATION, "validating");
}
}
See also:
Samples of Condition
Java Code
The method
evaluate has to be overridden:
public class NppCondition_IsValidationOK extends Condition
{
public boolean evaluateCondition(ConditionContext context) throws OperationException
{
String validation = context.getVariableString("validationResult");
boolean hasError = "KO".equals(validation);
return !hasError;
}
}
See also:
Sample of ConditionBean
Java Code
The method
evaluateCondition has to be overridden as in the following sample:
public class ConditionBean_IsBranchValid extends ConditionBean
{
private String branchName;
public String getBranchName()
{
return this.branchName;
}
public void setBranchName(String branchName)
{
this.branchName = branchName;
}
public boolean evaluateCondition(ConditionBeanContext aContext) throws OperationException
{
final Repository repository = aContext.getRepository();
Severity severityForValidation = Severity.ERROR;
String branchToTestName = this.getBranchName();
final AdaptationHome branchToTest = repository.lookupHome(HomeKey.forBranchName(branchToTestName));
if (branchToTest.getValidationReportsMap(severityForValidation) != null
&& branchToTest.getValidationReportsMap(severityForValidation).size() > 0)
{
return false;
}
return true;
}
}
See also:
Configuration through module.xml
The condition bean must be declared in
module.xml:
<module>
<beans>
<bean className="com.orchestranetworks.workflow.genericScriptTask.ConditionBean_IsBranchValid">
<documentation xml:lang="fr-FR">
<label>Branche valide ?</label>
<description>
Ce script permet de tester si une branche est valide.
</description>
</documentation>
<documentation xml:lang="en-US">
<label>Branch valid ?</label>
<description>
This script allows to check if a branch is valid.
</description>
</documentation>
<properties>
<property name="branchName" input="true">
<documentation xml:lang="fr-FR">
<label>Branche à contrôler</label>
<description>
Nom de la branche à valider.
</description>
</documentation>
<documentation xml:lang="en-US">
<label>Branch to check</label>
<description>
Branch name to check.
</description>
</documentation>
</property>
</properties>
</bean>
</beans>
</module>
Sample of SubWorkflowsInvocationBean
Java Code
public class MySubWorkflowsInvocationBean extends SubWorkflowsInvocationBean
{
@Override
public void handleCreateSubWorkflows(SubWorkflowsCreationContext aContext)
throws OperationException
{
final ProcessLauncher subWorkflow1 = aContext.registerSubWorkflow(
AdaptationName.forName("validateProduct"),
"validateProduct1");
subWorkflow1.setLabel(UserMessage.createInfo("Validate the new product by marketing"));
subWorkflow1.setInputParameter("workingBranch", aContext.getVariableString("workingBranch"));
subWorkflow1.setInputParameter("code", aContext.getVariableString("code"));
subWorkflow1.setInputParameter("service", aContext.getVariableString("marketing"));
final ProcessLauncher subWorkflow2 = aContext.registerSubWorkflow(
AdaptationName.forName("validateProduct"),
"validateProduct2");
subWorkflow2.setLabel(UserMessage.createInfo("Validate the new product by direction"));
subWorkflow2.setInputParameter("workingBranch", aContext.getVariableString("workingBranch"));
subWorkflow2.setInputParameter("code", aContext.getVariableString("code"));
subWorkflow2.setInputParameter("service", aContext.getVariableString("direction"));
// Conditional launching.
if (aContext.getVariableString("productType").equals("book"))
{
final ProcessLauncher subWorkflow3 = aContext.registerSubWorkflow(
AdaptationName.forName("generateISBN"),
"generateISBN");
subWorkflow3.setLabel(UserMessage.createInfo("Generate ISBN"));
subWorkflow3.setInputParameter(
"workingBranch",
aContext.getVariableString("workingBranch"));
subWorkflow3.setInputParameter("code", aContext.getVariableString("code"));
}
aContext.launchSubWorkflows();
}
@Override
public void handleCompleteAllSubWorkflows(SubWorkflowsCompletionContext aContext)
throws OperationException
{
aContext.getCompletedSubWorkflows();
final ProcessInstance validateProductMarketing = aContext.getCompletedSubWorkflow("validateProduct1");
final ProcessInstance validateProductDirection = aContext.getCompletedSubWorkflow("validateProduct2");
if (aContext.getVariableString("productType").equals("book"))
{
final ProcessInstance generateISBN = aContext.getCompletedSubWorkflow("generateISBN");
aContext.setVariableString("isbn", generateISBN.getDataContext().getVariableString(
"newCode"));
}
if (validateProductMarketing.getDataContext().getVariableString("Accepted").equals("true")
&& validateProductDirection.getDataContext().getVariableString("Accepted").equals(
"true"))
aContext.setVariableString("validation", "ok");
}
}
See also:
Configuration through module.xml
SubWorkflowsInvocationBean bean must be declared in module.xml:
<module>
<beans>
<bean className="com.orchestranetworks.workflow.test.MySubWorkflowsInvocationBean"/>
</beans>
</module>
Sample of WaitTaskBean
Java Code
public class MyWaitTaskBean extends WaitTaskBean
{
@Override
public void onStart(WaitTaskOnStartContext aContext)
{
Map<String, String> params = new HashMap<String, String>();
params.put("resumeId", aContext.getResumeId());
myMethod.callWebService(params);
}
@Override
public void onResume(WaitTaskOnResumeContext aContext) throws OperationException
{
// Defines a specific mapping.
aContext.setVariableString("code", aContext.getOutputParameters().get("isbn"));
aContext.setVariableString("comment", aContext.getOutputParameters().get("isbnComment"));
}
}
See also:
Configuration through module.xml
WaitTaskBean bean must be declared in module.xml:
<module>
<beans>
<bean className="com.orchestranetworks.workflow.test.MyWaitTaskBean"/>
</beans>
</module>
Sample of ActionPermissionsOnWorkflow
Java Code
package com.orchestranetworks.workflow.test;
import com.orchestranetworks.service.*;
import com.orchestranetworks.workflow.*;
import com.orchestranetworks.workflow.ProcessExecutionContext.*;
/**
*/
public class MyDynamicPermissions extends ActionPermissionsOnWorkflow
{
public ActionPermission getActionPermission(
WorkflowPermission aWorkflowAction,
ActionPermissionsOnWorkflowContext aContext)
{
if (WorkflowPermission.VIEW.equals(aWorkflowAction)
|| WorkflowPermission.CREATE_PROCESS.equals(aWorkflowAction))
return ActionPermission.getEnabled();
return ActionPermission.getDisabled();
}
}
See also:
Configuration through module.xml
ActionPermissionsOnWorkflow bean must be declared in module.xml:
<module>
<beans>
<bean className="com.orchestranetworks.workflow.test.MyDynamicPermissions"/>
</beans>
</module>
Sample of WorkflowTriggerBean
Java Code
public class MyWorkflowTriggerBean extends WorkflowTriggerBean
{
@Override
public void handleAfterProcessInstanceStart(
WorkflowTriggerAfterProcessInstanceStartContext aContext) throws OperationException
{
final DisplayPolicy policy = DisplayPolicyFactory.getPolicyForSession(aContext.getSession());
final MailSpec spec = aContext.createMailSpec();
spec.notify(NotificationType.TO, "supervisor@mail.com");
spec.setSubject("[TRIGGER] After process instance start");
spec.setBody("The workflow '"
+ policy.formatUserMessage(aContext.getProcessInstance().getLabel())
+ "' has been created.");
spec.sendMail(Locale.US);
}
@Override
public void handleBeforeProcessInstanceTermination(
WorkflowTriggerBeforeProcessInstanceTerminationContext aContext) throws OperationException
{
final DisplayPolicy policy = DisplayPolicyFactory.getPolicyForSession(aContext.getSession());
final MailSpec spec = aContext.createMailSpec();
spec.notify(NotificationType.TO, "supervisor@mail.com");
spec.setSubject("[TRIGGER] Before process instance termination");
spec.setBody("The workflow '"
+ policy.formatUserMessage(aContext.getProcessInstance().getLabel())
+ "' has been completed. The created product is: '"
+ aContext.getVariableString(NppConstants.VAR_CODE) + "'.");
spec.sendMail(Locale.US);
}
@Override
public void handleAfterWorkItemCreation(WorkflowTriggerAfterWorkItemCreationContext aContext)
throws OperationException
{
DisplayPolicy policy = DisplayPolicyFactory.getPolicyForSession(aContext.getSession());
MailSpec spec = aContext.createMailSpec();
spec.notify(NotificationType.TO, "supervisor@mail.com");
spec.setSubject("[TRIGGER] After work item creation");
WorkItem workItem = aContext.getWorkItem();
State state = workItem.getState();
String body = "The work item '" + policy.formatUserMessage(workItem.getLabel())
+ "' has been created. \n The step id is : " + aContext.getCurrentStepId()
+ ". \n The work item is in state : " + policy.formatUserMessage(state.getLabel());
if (workItem.getOfferedTo() != null)
body += "\n The role is :" + workItem.getOfferedTo().format();
if (workItem.getUserReference() != null)
body += "\n The user is :" + workItem.getUserReference().format();
spec.setBody(body);
spec.sendMail(Locale.US);
}
@Override
public void handleBeforeWorkItemStart(WorkflowTriggerBeforeWorkItemStartContext aContext)
throws OperationException
{
DisplayPolicy policy = DisplayPolicyFactory.getPolicyForSession(aContext.getSession());
MailSpec spec = aContext.createMailSpec();
spec.notify(NotificationType.TO, "supervisor@mail.com");
spec.setSubject("[TRIGGER] Before work item start");
spec.setBody("The work item '"
+ policy.formatUserMessage(aContext.getWorkItem().getLabel())
+ "' has been started. \n The current step id is : "
+ aContext.getCurrentStepId()
+ ". \n The work item user is: '"
+ DirectoryHandler.getInstance(aContext.getRepository()).displayUser(
aContext.getWorkItem().getUserReference(),
aContext.getSession().getLocale()) + "'.");
spec.sendMail(Locale.US);
}
@Override
public void handleBeforeWorkItemAllocation(
WorkflowTriggerBeforeWorkItemAllocationContext aContext) throws OperationException
{
DisplayPolicy policy = DisplayPolicyFactory.getPolicyForSession(aContext.getSession());
MailSpec spec = aContext.createMailSpec();
spec.notify(NotificationType.TO, "supervisor@mail.com");
spec.setSubject("[TRIGGER] Before work item allocation");
spec.setBody("The work item '"
+ policy.formatUserMessage(aContext.getWorkItem().getLabel())
+ "' has been allocated. \n The current step id is: "
+ aContext.getCurrentStepId()
+ ". \n The work item user is: '"
+ DirectoryHandler.getInstance(aContext.getRepository()).displayUser(
aContext.getUserReference(),
aContext.getSession().getLocale()) + "'.");
spec.sendMail(Locale.US);
}
@Override
public void handleBeforeWorkItemDeallocation(
WorkflowTriggerBeforeWorkItemDeallocationContext aContext) throws OperationException
{
DisplayPolicy policy = DisplayPolicyFactory.getPolicyForSession(aContext.getSession());
MailSpec spec = aContext.createMailSpec();
spec.notify(NotificationType.TO, "supervisor@mail.com");
spec.setSubject("[TRIGGER] Before work item deallocation");
spec.setBody("The work item '"
+ policy.formatUserMessage(aContext.getWorkItem().getLabel())
+ "' has been deallocated. \n The current step id is: "
+ aContext.getCurrentStepId()
+ ". \n The old work item user is: '"
+ DirectoryHandler.getInstance(aContext.getRepository()).displayUser(
aContext.getWorkItem().getUserReference(),
aContext.getSession().getLocale()) + ".");
spec.sendMail(Locale.US);
}
@Override
public void handleBeforeWorkItemReallocation(
WorkflowTriggerBeforeWorkItemReallocationContext aContext) throws OperationException
{
DisplayPolicy policy = DisplayPolicyFactory.getPolicyForSession(aContext.getSession());
MailSpec spec = aContext.createMailSpec();
spec.notify(NotificationType.TO, "supervisor@mail.com");
spec.setSubject("[TRIGGER] Before work item reallocation");
spec.setBody("The work item '"
+ policy.formatUserMessage(aContext.getWorkItem().getLabel())
+ "' has been reallocated. \n The current step id is: "
+ aContext.getCurrentStepId()
+ ". \n The work item user is: '"
+ DirectoryHandler.getInstance(aContext.getRepository()).displayUser(
aContext.getUserReference(),
aContext.getSession().getLocale())
+ "'. The old work item user is: '"
+ DirectoryHandler.getInstance(aContext.getRepository()).displayUser(
aContext.getWorkItem().getUserReference(),
aContext.getSession().getLocale()) + "'.");
spec.sendMail(Locale.US);
}
@Override
public void handleBeforeWorkItemTermination(
WorkflowTriggerBeforeWorkItemTerminationContext aContext) throws OperationException
{
DisplayPolicy policy = DisplayPolicyFactory.getPolicyForSession(aContext.getSession());
MailSpec spec = aContext.createMailSpec();
spec.notify(NotificationType.TO, "supervisor@mail.com");
spec.setSubject("[TRIGGER] Before work item termination");
spec.setBody("The work item '"
+ policy.formatUserMessage(aContext.getWorkItem().getLabel())
+ "' has been terminated. \n The current step id is: " + aContext.getCurrentStepId()
+ ". \n The work item has been accepted ? " + aContext.isAccepted());
spec.sendMail(Locale.US);
}
}
See also:
Configuration through module.xml
WorkflowTriggerBean bean must be declared in module.xml:
<module>
<beans>
<bean className="com.orchestranetworks.workflow.test.MyWorkflowTriggerBean"/>
</beans>
</module>
Sample of trigger starting a process instance
Sample
public class TriggerWorkflow extends TableTrigger
{
public void handleAfterModify(AfterModifyOccurrenceContext aContext) throws OperationException
{
ValueContext currentRecord = aContext.getOccurrenceContext();
String code = (String) currentRecord.getValue(Path.parse("/code"));
//Get published process
PublishedProcessKey processPublishedKey = PublishedProcessKey.forName("productProcess");
//Defines process instance
WorkflowEngine engine = WorkflowEngine.getFromProcedureContext(aContext.getProcedureContext());
ProcessLauncher launcher = engine.getProcessLauncher(processPublishedKey);
//initialize Data Context
launcher.setInputParameter("code", "/root/Client[./code=\"" + code + "\"]");
launcher.setInputParameter("workingBranch", aContext.getAdaptationHome().getKey().getName());
//Starts process
launcher.launchProcess();
}
//...
}