Oracle Waveset 8.1.1 Deployment Reference

Using Workflow Services

Waveset contains default workflows to define the process for provisioning and manipulating user accounts. When customizing Waveset, you can modify these workflows to reflect the business rules that are unique to your deployment environment. Workflow allows you to implement unique business rules for account provisioning in Waveset.

This section provides a high level discussion of the following workflow service-related topics:

For information on specific workflow methods, see <distribution>\REF\javadoc, where <distribution> is your installation directory.

Understanding Method Context

The Lighthouse context represents an authenticated session to access the Waveset repository, which is subject to authorization checking to enforce visibility and action restrictions. Creating, modifying, and deleting users and other Waveset objects requires authenticated access to the repository provisioner. This access is established by a context object, typically a LighthouseContext, or a WorkflowContext. Each of these context objects contains an authenticated session object that gives the caller access to the repository.

A context (or Session) is fairly intuitive when operating in the context of a logged in environment -- specifically, in a web browser. But within Waveset, a workflow is a separate process (actually a TaskInstance), and independent from any browser session, must still access the Waveset repository. This is possible because the executing workflow has an active context that is assigned to the workflow when it starts and can be persisted/restored with the workflow when it suspends/resumes.

When a user interacts with a workflow (typically through a WorkItem or ManualAction), the workflow maintains its own context. It does not assume the context of the user interacting with the WorkItem (although that user must possess a context that gives them appropriate access to the WorkItem). If the user interacting with the WorkItem causes a form to be loaded, Waveset processes the form with the context of the user, not the context of the workflow. To be more precise, the user interacting with the WorkItem is not interacting with the workflow at all. The user is simply interacting with the WorkItem. After the user modifies the WorkItem, the Scheduler will restart the workflow if appropriate.

Built-In Workflow Variables

The workflow engine uses several built-in variables. Most of these variables do not need to be declared in the workflow. However, you can use built-in variables to find out the state of the workflow execution. In addition, many variables are set as a side effect of workflow services.


Note –

Workflow variables are case-sensitive. For example, WF_ACTION_ERROR is not the same as wf_action_error.


Table 1–12 Built-In Variables

Name  

Description  

WF_ACTION_ERROR

A built-in variable that will be set to true if the previously executed action returned a result containing an error or a thrown exception.

WF_ACTION_RESULT

A built-in variable that will be set to the WavesetResult object returned by the previous action. Use this variable when you want to capture the action’s WavesetResult and process it without adding it to the global TaskInstance result. This variable was originally added to support resource retries, where you do not necessarily want to keep adding the resource error messages to the task result on every retry. It is not used often, but can be useful if you ever want to tweak the action result before adding it to the task result. 

WF_ACTION_SUPPRESSED

This built-in variable will be set to true if the action was suppressed due to a <Condition> expression evaluating to false. 

WF_ACTION_TIMEOUT

A built-in variable that will be set to true if the previously executed action timed out. 

WF_CASE_OWNER

A built-in variable that contains the name of the administrator who launched the workflow task. 

WF_CASE_RESULT

A built-in variable that contains the WavesetResult of the TaskInstance. This can be used in actions implemented in XPRESS or JavaScript to retrieve the result. For actions that are implemented as WorkflowApplication classes, they can obtain the result through the WorkflowContext. Because the entire WorkflowContext is exposed through the WF_CONTEXT variable, this is not absolutely necessary, but convenient. 

WF_CONTEXT

A built-in variable that contains a WorkflowContext object. You can use this in actions implemented in XPRESS or JavaScript to retrieve the WorkflowContext. For actions that are implemented as WorkflowApplication classes, the context is passed in. 

General Session Workflow Services

The com.waveset.session.WorkflowServices class contains a set of services that support a range of operations, including general operations (get, checkout, checkin, etc.) on views and objects.

General Session Workflow Services Call Structure

Workflows have an internal hierarchical structure that constrain both flow of control and scope of variables. A workflow (also called a Case or WFCase) contains a list of workflow Activity elements. A workflow activity contains a list of Action elements. A variable declared at the WFCase is visible to all Activity and Action elements. If a variable named color is declared at the WFCase level, and then again in an Action, they are effectively two different variables, such that changing the value of the color variable in the Action will not affect the value of the color variable from the WFCase.

Workflow services are called from workflow actions. WorkflowServices provides a set of operations that are selected through the value of the op Argument. Each operation can have a different set of arguments, so the calling ’signature’ must match the specified service itself. The general form of a workflow service action is shown in the following code example:

<Action class=’com.waveset.session.WorkflowServices’>
   <Condition/>
   <Argument name=’op’ value=workflowServiceOp/>
   <Argument name=argname1>
      <expression>value1expression</expression>
   </Argument>
   <Argument name=argname2>
      <expression>value2expression</expression>
   </Argument>
   <Argument name=argnameN>
      <expression>valueNexpression</expression>
   </Argument>
</Action>

Each of the supported workflow services has a variable number of required and optional arguments. The op argument to the session workflow services call must specify one of the provided services. This is similar to calling a method by reflection, where the name of the method to be called is similar to the name of the workflow service to be executed.

If an op argument is given that is not on the following list, the workflow services return:

’Unknown WorkflowServices op’

and the workflow context variable WF_ACTION_ERROR will be non-null.

If an op argument is given that is not on the preceding list, a workflow service returns:

’Unknown WorkflowServices op’

and the workflow context variable WF_ACTION_ERROR will be non-null.

Supported Session Workflow Services

The com.waveset.session.WorkflowServicesJavadoc for workflow services documents the internal Waveset Java string fields rather than the nomenclature required by XPRESS. For example, the documentation for the workflow services operation addDeferredTask is provided by the Javadoc for the WorkflowServices OP_ADD_DEFERRED_TASK string field. In general, to find the Javadoc for an operation, take the operation name, capitalize and separate with an underscore the words making the operation name, and prefix the result with the OP_. Operation argument names are treated similarly, but prefixed with ARG_.

Provision Workflow Services

The com.waveset.provision.WorkflowServices class also contains a set of services, although they are used less often than the methods in com.waveset.session.WorkflowServices. These are the low-level primitives for performing account management, and they are primarily called by the default workflows. In a custom workflow, you might want to use these services, or you might prefer to use the higher level views with checkoutView and checkinView, which will in turn launch the stock workflows.

The primary purpose of the provision services is to give workflows access to the Provisioner, which in turn has access to resources and resource accounts. These are the services that actually perform the read/write operations on the resources themselves.

General Provision Workflow Services Call Structure

Workflows have an internal hierarchical structure that constrain both flow of control and scope of variables. A Workflow (also called a Case or WFCase) contains a list of Workflow Activity. A Workflow Activity contains a list of Actions. A variable declared at the WFCase is visible to all Activity and Action elements. If a variable named ’color’ is declared at the WFCase level, and then again in an Action, there are effectively two different variables, such that changing the value of the ’color’ variable in the Action will not affect the value of the ’color’ variable from the WFCase. Workflow services are called from workflow actions. WorkflowServices provides a set of ’operations’ that are selected through the value of the ’op’ Argument. Each operation may have a different set of arguments, so the calling ’signature’ must match the service itself. The general form of a session workflow service action is shown in the following code example:

<Action class=’com.waveset.provision.WorkflowServices’>
   <Condition/>
   <Argument name=’op’ value=workflowServiceOp/>
   <Argument name=argname1>
      <expression>value1expression</expression>
   </Argument>
   <Argument name=argname2>
      <expression>value2expression</expression>
   </Argument>
           …
   <Argument name=argnameN>
      <expression>valueNexpression</expression>
   </Argument>
</Action>

Each supported workflow services will have a variable number of required and optional arguments.

Supported Provision Workflow Services

The com.waveset.provision.WorkflowServices Javadoc contains information about currently supported provision workflow services. The op argument to the workflow services call must be one of these values.

If an unsupported op argument is given, a workflow service returns:

”Unknown WorkflowServices op’

and the workflow context variable WF_ACTION_ERROR will be non-null. Provision and session workflow services map XPRESS operations to argument names in the same way.

Understanding the View Operation Methods

Because most workflow processing involves views, the most common view-related methods used in workflows are the checkoutView and checkinView methods. Checking out a view object will lock the underlying object such that no other user can write to it. This is especially important in workflow processing because a workflow may check out (lock) a user, and then suspend due to a manual action, leaving the user locked until the manual action is serviced (which could be hours or days later). By default, locks on objects expire in 5 minutes, which poses a second concern for workflows. A check in of an object requires that the caller already have the object locked. So a workflow that checks out a view (implicitly locking the object), suspends for 10 minutes, and the checks in the view will fail because the callers lock will have been aborted due to the 10 minute delay.

The following example shows a typical checkout operation:


<Action id=’-1’ application=’com.waveset.session.WorkflowServices’>
   <Argument name=’op’ value=’checkoutView’/>
   <Argument name=’type’ value=’User’/>
   <Argument name=’id’ value=’mfairfield’/>
     <Variable name=’view’/>
   <Return from=’view’ to=’user’/>
</Action>

Using map of options with Checkout and Checkin Calls

It can be challenging to determining which options you can use as optional arguments (which are defined as part of the UserViewConstants class) for these check out and check in calls. The Javadocs list options in this format:

OP_TARGETS

OP_RAW

OP_SKIP_ROLE_ATTRS

Instead of hard-coding these literal strings in your code when checking for options, Waveset provides constants that you can use throughout your code to represent a string. While this is a good coding practice, you cannot reference the static fields of UserViewConstants, such as OP_TARGET_RESOURCES, through XPRESS or workflow.

To identify valid strings that you can pass in the correct value, you can write a test rule that reveals the true string. For example, the following rule returns TargetResources.


<block>
   <set name=’wf_srv’>
      <new class=’com.waveset.provision.WorkflowServices’/>
   </set>

   <script>
      var wfSvc = env.get( ’wf_srv’ );
      var constant = wfSvc.OP_TARGETS;
      constant;
   </script>
</block>

Although handy for finding out a string, this rule is not appropriate for production deployment because it returns the same string for every call made to it. To minimize this problem, Waveset constants that are used in view processing are never changed. Once you have coded the constant in your workflow, the view’s interpretation of that constant will not change from release to release.

One you have identified valid strings, you can update your checkout view call as follows. The following code checks out a view that propagates only changes to Waveset and Active Directory.


<Action id=’-1’ application=’com.waveset.session.WorkflowServices’>
   <Argument name=’op’ value=’checkoutView’/>
   <Argument name=’type’ value=’User’/>
   <Argument name=’id’ value=’mfairfield’/>
   <Argument name=’options’>
      <map>
       <s>TargetResources</s>
       <list>
          <s>Lighthouse</s>
          <s>AD</s>
       </list>
     </map>
   </Argument>
<Variable name=’view’/>
<Return from=’view’ to=’user’/>
</Action>

Best Practices

From a performance perspective, best practice suggests limiting the size of the User view whenever possible. A smaller view means less data is pulled from the resource and sent over the network. Because the view is held as a variable in the workflow, any time the workflow task is suspended the view must be written to the TaskInstance object. If a system is running thousands of workflows concurrently, and each workflow contains large views, the amount of time spent transferring the view to/from the repository (which includes serialization/deserialization) becomes a significant bottleneck.

The best use of a view is to carry only enough data necessary to allow changes to the user to be made and approved intelligently. If the intent of the caller is to change a user’s password on a set of resources, all that is necessary to know to drive this process is a list of accounts associated with the user. Specific account data would not typically be necessary for this process.

Sample Scenario One

A customer might decide to implement a custom workflow so that users can request access to a particular resource, that workflow should check out the User view to allow a change to be submitted to it (pending the appropriate approval). In this example, the only information that probably must be available is the Waveset User portion of the view so that the waveset.resources list and the accountInfo object can be updated appropriately. In this situation, use the TargetResources option when checking out the User view to check out only the Waveset User portion of the User view with an option map similar to the following:


<map>
   <s>TargetResources</s>
   <list>
      <s>Lighthouse</s>
   </list>
</map>

You can reduce the size of the User view in the WorkItem view. Work items are the objects that represent a task assigned to an individual such as an approval, a delegation, or simply an interruption in a workflow to allow a user to input additional information. Custom workflows create approvals and interact with forms through manual actions. In short, a manual action copies all Workflow variables that are in the scope of the current <ManualAction> element. In addition to the task context, into a variables object within the WorkItem object. In terms of approvals, you rarely need the full User view and context variables. As a result, consider reducing the WorkItem size by specifying the ExposedVariables argument when defining a ManualAction.

The <Exposed Variables> element tells the workflow exactly which variables are necessary to capture in the WorkItem for subsequent processing. Remember that if a single workflow supports multiple approvers, Waveset will create multiple work items (one for each approver).

Sample Scenario Two

The preceding scenario shows a relatively uncomplicated implementation of single manual action. But typical deployments involve more complicated scenarios. For example, a customer might require that when a user is created, an approval goes to a ”bucket’, where one of approximately 25 approvers can select the approval. To mimic a bucket, you can create a work item for each approver in the bucket. All an approver must do is accept the action. Once accepted, Waveset can discard the remaining 24 work items, and generates the actual approval work item for the approver who accepted the bucket request.

Consider that there are a total of three buckets that act as escalation tiers. When the approval is processed through Bucket 1, Waveset escalates a new request into Bucket 2, and the process begins again. This process results in approximately 26 work items per bucket (25 + 1) multiplied by three (for three buckets). One user request would create 78 work items, granted not all at once. But then consider this occurring in a deployment environment containing a user base of 500,000 users with hundreds of these requests flowing in each day. Had the implementer of this scenario not bothered to size the WorkItem views by using the ExposedVariables argument, Waveset would store a large amount of bit of non-essential data in the work items and being passed over the JDBC connection.


<Activity id=’0’ name=’activity1’>
   <ManualAction id=’-1’>
      <FormRef>
         <ObjectRef type=’UserForm’ name=’Access Review Abort Confirmation Form’/>
      </FormRef>
      <ExposedVariables>
         <List>
            <String>user.waveset.accountId</String>
            <String>user.waveset.resources</String>
            <String>user.accounts[Lighthouse].idmManager</String>
            <String>user.accounts[Lighthouse].fullname</String>
         </List>
      </ExposedVariables>
      <ViewVariables>
         <List>
            <String>user</String>
         </List>
      </ViewVariables>
   </ManualAction>
   <WorkflowEditor x=’53’ y=’111’/>
</Activity>

Sample Scenario Three

You must write a custom user provisioning request workflow for users to execute. This type of workflow might be handy when customers want managers to submit provisioning requests for their direct reports but prefer to avoid making every manager in the organization an Waveset administrator.

With these requirements in mind, you create a custom workflow that:

You will also need to refresh the view. Refreshing the view means that Waveset re-examines the assigned resource information and re-fetches that information from the native resources to update the User view with the latest information (if it changed since view check-out).

You can ensure that Waveset refreshes the view by specifying a ViewVariables element within the manual action that instructs Waveset which variables in the WorkItem’s variables object should be treated as a view and thus refreshed when requested. See the preceding example for an example of specifying the variable user as a ViewVariable.

Using WorkItem Variables: Summary

As you can see from the preceding scenarios, you can control the size of WorkItem objects through the careful use of top-level variables. Waveset creates a WorkItem object for each manual action that is processed in a workflow. By default, these objects contain a copy of all top level variables from the executing workflow. There are three ways to control the variables that are passed into and assimilated back from WorkItem objects:

ExposedVariables

You can use ExposedVariables to control which variables from the workflow are copied into the WorkItem object. If you have defined ExposedVariables, only those variables in the list are copied to the WorkItem. Using this option controls the size of WorkItem objects reducing memory usage, database size, and CPU processing time. The definition should be a list containing string representations of the workflow variables. Two example definitions follow.

<!-- Pass the entire view object but no other WF variables -->
<ExposedVariables>
  <List>
     <String>userView</String>
  </List>
</ExposedVariables>


<!-- More optimized to only pass the Lighthouse attributes and 
     email value -->
<!-- Note the definition of a partial GenericObject path and a complete 
     GenericObject path -->
<ExposedVariables>
   <List>
     <String>userView.accounts[Lighthouse]</String>
     <String>userView.waveset.email</String>
     <String>managerFlag</String>
   </List>
</ExposedVariables>

Passing only the data that the UserForm requires to operate optimizes the WorkItem processing time. This reduces the time required when processing the workItemEdit.jsp and also reduces total memory consumption and GC activities for the JVM. Without this option, the system can quickly consume a large amount of CPU time during concurrent user operations.

EditableVariables

You can use EditableVariables to control which variables from the WorkItem object are assimilated back into the workflow. The classic usage of this definition is to control which variables can be edited by the approver. EditableVariables is most useful during parallel approvals to prevent two approvers from overwriting the same data. Make sure you read the note regarding ExposedVariables.

<ExposedVariables>
<List>
   <String>userView.accounts[Lighthouse]</String>
   <String>userView.waveset.email</String>
</List>
</ExposedVariables>
<!-- Only the firstname, lastname fields should be assimilated 
     from the WorkItem -->
<-- Note the inclusion of the formButton variable which is used to 
    store the button value -->
<EditableVariables>
<List>
   <String>userView.accounts[Lighthouse].firstname</String>
   <String>userView.accounts[Lighthouse].lastname</String>
   <String>formButton</String>
</List>
</EditableVariables>
<Field button='true'>
   <Display class='Button'>
      <Property name='name' value='variables.formButton'/>
      <Property name='label' value='Submit'/>
      <Property name='command' value='Save'/>
      <Property name='value' value='submit'/>
   </Display>
</Field>

To debug, see workflow.fileTrace attribute of the System Configuration object to identify which variables are being assimilated back into Workflow from the view. ViewVariables is used to control which variables represent view objects which should be refreshed when a refreshView operation is executed from the workItemEdit.jsp page. In general a refreshView operation reloads the view data from all of its sources such as resource adapters.

ViewVariables

You can use ViewVariables to control which variables represent view objects that should be refreshed when a refreshView operation is executed from the workItemEdit.jsp page. In general, a refreshView operation reloads the view data from all of its sources such as resource adapters.

<!-- The userView variable should be refreshed during a refreshView -->
<ViewVariables>
   <List>
      <String>userView</String>
   </List>
</ViewVariables>

Tip –

Use ViewVariables only when absolutely necessary for correct form and user interaction. This is option is seldom used.