The workflow offers two types of steps: 'library' or 'specific'.
'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.
Step | Library | Specific |
---|---|---|
Scripts | ScriptTaskBean | ScriptTask |
Conditions | ConditionBean | Condition |
User task | UserTask |
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()); } } |
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()); } } |
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 > |
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 > |
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" ); } } |
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; } } |
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 ; } } |
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 > |
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" ); } } |
SubWorkflowsInvocationBean
bean must be declared in module.xml
:
< module > < beans > < bean className = "com.orchestranetworks.workflow.test.MySubWorkflowsInvocationBean" /> </ beans > </ module > |
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" )); } } |
WaitTaskBean
bean must be declared in module.xml
:
< module > < beans > < bean className = "com.orchestranetworks.workflow.test.MyWaitTaskBean" /> </ beans > </ module > |
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(); } } |
ActionPermissionsOnWorkflow
bean must be declared in module.xml
:
< module > < beans > < bean className = "com.orchestranetworks.workflow.test.MyDynamicPermissions" /> </ beans > </ module > |
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); } } |
WorkflowTriggerBean
bean must be declared in module.xml
:
< module > < beans > < bean className = "com.orchestranetworks.workflow.test.MyWorkflowTriggerBean" /> </ beans > </ module > |
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 ProcessLauncher launcher = ProcessLauncherHelper.createLauncher( processPublishedKey, aContext.getProcedureContext()); //initialize Data Context launcher.setInputParameter( "code" , "/root/Client[./code=\"" + code + "\"]" ); launcher.setInputParameter( "workingBranch" , aContext.getAdaptationHome().getKey().getName()); //Starts process launcher.launchProcess(); } //... } |