Swimlanes

Introduction

A Swimlane is an editor Component that allows definingAccess Control over Process Tokens. Through a Swimlane, you can choose which Participants are allowed to access the Tokens placed on the components contained in the Swimlane itself. A Swimlane Participant can be either a single User, a Group, or Role (see Users, Groups and Roles). The Participant value can also be determined at runtime through a script. Moreover, a Sentry expression can be added to enforce Access Control conditions that cannot be expressed via a single User, Group or Role.

Adding a Swimlane

  1. To add a Swimlane to your Process, you can either:
  • Right-click on an empty place in the Editor and select Add Swimlane from the context menu.
  • Drag a Swimlane from the Component Library onto the Process Model.

  1. Set the properties of your Swimlane (see Swimlane Properties ).
  2. To adjust the position and size of the Swimlane, move the cursor over the Swimlane header and drag it to another position. Click on the bottom border of the Swimlane and drag the cursor to change the Swimlane height.
  3. To delete a Swimlane, right-click on it and select Delete Element from the context

Swimlane Properties

Property Description
Task List Name Task name as displayed in a Task List or in FNZ Studio Runtime
Color Swimlane color
Participant (Required) This property defines Access Control conditions on the token for user/s at design time. Select a User, Group or Role (Users, Groups and Roles) associated with the Sub-Process from the dropdown list, or enter a script to define such user/s).
Sentry Evaluation

This property defines when the conditions set in the Sentry property below are evaluated:

  • Never: Sentry conditions are not evaluated, and Access Control is determined by the Participant property only.
  • At every access: Sentry conditions are evaluated at every access, after checking the Access Control conditions set in the Participant property.
Note: The script is executed every time a new token is generated on a component included in the Swimlane. The script is not be executed while the token is set on the same component.

Sentry

This property defines further Access Control conditions for user/s (in addition to the conditions defined in the Participant field):

  • Process:SwimlaneSentryState.DENY_ACCESS(): denies access to user/s
  • Process:SwimlaneSentryState.ALLOW_ACCESS(): grants access to user/s. The definition of a Sentry on the Swimlane is highlighted by the SwimlaneSentryIcon.png icon on the process Editor (this icon is also displayed in the Sentry column under Solution Maintenance > Process Tokens). The Sentry expression does not have access to the Value Store (e.g., it cannot read the Variables defined in the Process), therefore we recommend using User Preferences, Process Instance Attributes, or Token Attributes to define the logic in the script.

Workqueues

When a Token reaches an activity included in a Swimlane with a Participant, the activity needs to be assigned to a Workqueue. A Workqueue is a virtual object, defined only by its name. There are implicit Workqueues for Users, Groups and Roles:

  • The name of a Workqueue for a User is equal to the User Id.
  • The names of Workqueues for Roles and Groups look like GROUP:GroupName and ROLE:RoleName.

By using expressions on a Swimlane, a Task can be assigned to an arbitrary Workqueue. The expression is expected to return a String. The result is treated as Workqueue name.

Example Expressions:

Copy
'ROLE:LegalOfficer'

IF($amount > 1000,'GROUP:Compliance','GROUP:Backoffice')

GetSupervisor($employeeId)

'User1234'

The Expression is evaluated whenever a Participant Activity is enabled in the Swimlane. The result of the evaluation determines the Workqueue name for the current Activity, but has no effect on other, existing Tasks in the same Swimlane. The information to which Workqueue an Activity has been assigned is saved in the Token.

The value of the Workqueue of a specific Process Token at runtime can be inspected in FNZ Studio Composition under Solution Maintenance > Process Instances > [Process Instance] > Details > Tokens tab > [Token] > View. The Workqueue is shown in the Queue Name field.

The Workqueue of a Token can be changed through reassignments. Reassignment can be performed either by clicking the Assign button on the Token, or through a Script Functions such as AssignWorkitemToUser.

Note: if the Participant is defined through an expression, the expression is re-evaluated whenever a new Activity is enabled in the Swimlane, therefore the effect of a previous reassignment may be overridden.

Workqueues.png

Note on Sentries Upon access, after checking the Participant/Workqueue conditions, the Sentry expression (if set) is evaluated. The return value of the Sentry expression defines whether access to the token is granted or denied. An example of Sentry expression could be a condition that checks the value of a user preference against the value stored in the Process Instance attributes.

An example of a Sentry expression is:

Copy

Integer $requiredAccessLevel := TOINTEGER(ProcessInstanceGetAttribute(ProcessInstanceId(), 'level'));

Integer $userAccessLevel := User:Get(User:CurrentUserGetId()).getPreference('level');

If $userAccessLevel >= $requiredAccessLevel Then

   Return Process:SwimlaneSentryState.ALLOW_ACCESS();

Else

   Return Process:SwimlaneSentryState.DENY_ACCESS();

End

Use Cases

Assigning a Swimlane to the Current User

Let's suppose you want to set the participant user expression of a Swimlane to the User who initiates the first task in that Swimlane.

It is fairly easy to access the current user in context in FNZ Studio, as the Platform provides the following two functions out of the box:

  • User:Get() – Returns the currently logged-in User object (providing access to all the User’s attributes like the userId, first and last name, and user preferences)
  • User:CurrentUserGetId() – Returns the userId of the currently logged-in User

The two functions above retrieve the User from a thread local variable set when the User establishes a new session with the server.

Potential Issues

There are many scenarios where the User:Get() and the User:CurrentUserGetId() functions are adopted as an easy solution to access the current user. In most of those scenarios, however, the developer perhaps forgets to consider the consequences in case those operations are executed when a user is not in context.

For this reason it is recommended you ask yourself the following questions before using the User:Get() or the User:CurrentUserGetId() functions:

  • Is this function always called in the context of an HttpRequest?
  • Is there any potential troubleshooting activity on the backend that triggers a call to this function?
  • Does my script still behave properly even if the function returns null?

Whenever the User:Get() and User:CurrentUserGetId() functions are called in the context of an HttpThread, they correctly return the current, logged-in User who submitted the request.

If those functions are called by a background thread, however, they do not have access to the aforementioned HttpThread local variable. This means the return value generated by a background thread will be null.

The following two example scenarios examine the issues in more detail.

Scenario #1 — Redirects

In this Process, the developer assumes that the User starts the task by clicking on a link or on a button, triggering an HTTPRequest.

A simple example Process, with two placeholders and redirect task in the middle

The first task ('Now') is correctly assigned to the User who clicked the link. After the Redirect Task, however, the Process Tokens are managed by a background thread — a thread that does not have access to the current user in context (as, technically, the user is not in context anymore).

For this reason, the second task ('Later') is suspended: The engine is not able to evaluate the participant user expression set on the Swimlane when the token gets there. This situation is shown in the following figure:

task suspended screenshot

A suggested solution is to define a variable (e.g. $creator), the value of which defaults to User:CurrentUserGetId(), but that "remembers" the value returned by the User:CurrentUserGetId() function at the time the Process was started - and keeps it in case any background processing happens. This approach is illustrated in the figure below:

An image showing the $creator variable definition and its usage in a Swimlane

Scenario #2 — Calls

Even if there is no Redirect or Intermediate task that hands over the control to a background thread it is still not a good idea to use the User:CurrentUserGetId() function directly in the Swimlane's Participant User Expression.

A simple example Process, with two placeholders and a Script task in the middle

The call to the backend system illustrated in the figure above can fail, leading to the system administrator needing to issue a 'retry' action from the console:

scenario console retry screenshot

Unfortunately, even if the retry operation is successful, this scenario also sees the execution of the retry handled by a background thread (because the original creator of the task is gone). With a Process design such as that illustrated above, the Process is again suspended due to the missing participant in the Swimlane expression.

scenario suspended screenshot

In this case, it is recommended to:

  1. Introduce appropriate null checks
  2. Use other techniques, such as the one explained in the first scenario, that can mitigate the risk of a "null" user in context

Implementing Server-side Validation for Swimlane Participants

Many business processes have a point where a user must submit the current case to another user. Examples:

  • A compliance officer has to review an account opening contract
  • A team manager has to approve a vacation request

In some processes, the current user may pick the next user from a list of available persons. The "available" option usually means that there are some business rules restricting the set of potential recipients. Examples:

  • A bank employee may select only a compliance officer located at the same branch
  • A money transaction has to be reviewed by another team member

Following, we explain how to check how to ensure your implementation is secure.

Dropdown List Example

Solutions may use a Dropdown List Screen Component populated with the list of permitted recipients.

dropdown list screen component populated

The Dropdown List values usually come from a Catalog Business Object, or get generated dynamically with some script code. The Dropdown List shows the person's full name; but if the page is submitted, it sends the selected person's user ID to the server. On the server side, this value is saved in a variable such as $forwardUserId. The variable is then used in a Swimlane expression in order to assign subsequent Process activities to the selected person.

Unfortunately most of these options outlined above have a big security flaw.

IMPORTANT!: The fact that the dropdown list only contains legal values when the page is rendered does not guarantee that one of these specific values will be submitted to the server.

In most Solutions, the value submitted from the client to the server is blindly accepted and saved in the variable without further validation. However, there are many ways to manipulate an HTML page and influence the data submitted to the server.

Most browsers are shipped with a web developer tool which allows users to view the HTML source code and change the HTML document, including form field values. It requires only very low technical skills to manipulate the content of a dropdown list in a web site. Users could easily add an additional entry with their own user ID or a user ID of an accomplice, select this entry and then submit the page.

dropdown list screen component values code

As a result, the user is in full control when it comes to which person the case is forwarded to: Users could approve their own account openings or vacation requests.

First of all, you should check if the user really must be able to select the recipient. It may be better to hard-code an assignment to a team (group of users) and have a kind of 'inbox' for the users in this team where team members can pick up cases and work on them.

If this is not possible, you must add a validator to the Dropdown List and make sure that the submitted value is a user ID of a permitted recipient. This usually means that you have to duplicate a part of the logic used to generate the Dropdown List values.

Radiobutton Example

Note that this issue does not just affect Dropdown Lists and 'Forward to User' implementations. Other form elements such as Radiobuttons or Checkboxes may be manipulated as well. If a Solution contains a Radiobutton List to pick an interest rate and blindly stores the selected rate in a variable, a user could manipulate the Radiobutton values and submit a much higher or much lower interest rate.

To prevent this, implement server-side validation, again by using a validator on the Radiobutton component.

A simple example of such a validator would be a Script Expression checking if the user selected is among the permitted choices.

In the Screen Editor, select the radiobutton component, go to the Display tab and set the validator to "Condition"

Now, manipulation done on the client-side cannot go past validation.

Nice try, Batman.

Reassigning a Token Owner

A possible use case you may have is to build a "Reassign" functionality in the FNZ Studio Portal that allows the owner of a task to reassign it to another user.

By using the AssignWorkitemToUser out-of-the-box function, the reassignment works at first: the target user receives the task and is able to work on it. However, When the user clicks the Next button in the Screen and moves the Token to the next activity in the same Swimlane, the Token is assigned to the previous owner.

This issue occurs due to the out-of-the-box function in FNZ Studio, which assigns the specified Token to the specified User (AssignWorkitemToUser). However, this function does not automatically update the Swimlane expression, rather the developer must tell the function how to update the Swimlane expression.

As a result, when a developer just uses the function defaults: 

  1. The current token is reassigned to the target specified user.
  2. When the new user clicks Next and advances the token to the next Screen in the same Swimlane, the Swimlane participant expression is re-evaluated and the token is reassigned to the previous owner.

Using Parameter variableAssignments

The AssignWorkitemToUser function provides an optional parameter called variableAssignments. This parameter lets you assign some variables in the target Process Value Store to update the Swimlane participant expression. The behavior of this additional parameter differs between versions of FNZ Studio.

This optional parameter can be used to set any number of variables in the target Process Value Store. This can also be done by evaluating an expression passed as an input to the function, which is going to be recognized and evaluated in the context of the target Value Store.

For projects running on these versions of FNZ Studio, the suggested implementation is the following:

Copy
Function ReassignOwner(String $workitemId, String $forwardUserId, String $workflowInstanceId := '') : Nothing Begin
   Workitem $workitem;
   If EMPTY($workflowInstanceId) Then
      $workitem := WORKITEM($workitemId);
   Else
      $workitem := WORKITEM($workitemId, $workflowInstanceId);
   End
   If $workitem != null Then
      String $theWorkFlowId := $workitem.getWorkflowId();
      String $oldUserId := $workitem.getUserId();
      String $swimlaneName := $workitem.getSwimlaneName();
      Local Named Any $map;
      $map := {}:Any;
      If $forwardUserId != $oldUserId Then
         String $ownerExpression := GetParticipantUserExpression($workitem);
         If $ownerExpression!= null && STARTSWITH($ownerExpression, '$') Then
            $map[$ownerExpression] := $forwardUserId;
            AssignWorkitemToUser($workitemId, $forwardUserId, $map, true);
         End
      End
   End
End

Where the function GetParticipantUserExpression is implemented as follows:

Copy
Function GetParticipantUserExpression(Workitem $workitem) : String Begin
   If $workitem == null Then
      Return null;
   End
   String $expression := $workitem.getParticipantUserExpression();
   If $expression == null Then
      String $workflowInstanceId := $workitem.getWorkflowInstanceId();
      WorkflowToken $parent := ProcessToken($workitem.getTokenId(), $workflowInstanceId).getParentWorkflowToken();
      If $parent == null Then
         Return null;
      Else
         Return GetParticipantUserExpression(WORKITEM($parent.getId(), $workflowInstanceId));
      End
   Else
      Return $expression;
   End
End

IMPORTANT!

Regardless of which version of FNZ Studio you are using, the functions provided only work correctly if there are no parallel activities in the current Swimlane.

If the Swimlane has parallel tasks (i.e. multiple Tokens), using the function results in an update of the Swimlane participant expression — which updates the ownership of all the Tokens in the Swimlane as soon as they are "moved" in the Swimlane context. There isnot a satisfactory solution to this issue beyond splitting up the Swimlane, or making sure it is ok that all the tokens are reassigned simultaneously.