Showing posts with label workflow. Show all posts
Showing posts with label workflow. Show all posts

Thursday, December 04, 2014

ISIM Workflow Extensions

During recent ramblings, I mentioned that I would publish some of my favourite ISIM workflow extensions. The workflow extensions that are provided "out of the box" cover tasks such as adding, modifying and deleting accounts and identities as well as enforcing policy and other standard operations. However, the "out of the box" list could do with having a number of useful extensions added.

One of my favourites (and something I pretty much insist on being installed as soon as I've deployed ISIM) is my version of a sendmail. ISIM has the ability to send emails, but only to those identities who have an email address. However, what if you wanted to send an email to an address which was not attached to any identity? What if you wanted to email a user during a self-registration workflow at which point the identity has not yet been created?

My sendmail extension is just a handful of lines long, uses standard ISIM methods and takes just the following arguments: eMail Address, Subject and Body.

The code is very simple indeed:

public ActivityResult sendMail(String mailAddress, String mailSubject, String mailBody) {
  try {
    List<String> addresses = new ArrayList<String>();
    addresses.add(mailAddress);
    NotificationMessage nMessage = new NotificationMessage(addresses, mailSubject, mailBody, mailBody);

    MailManager.notify(nMessage);

    return new ActivityResult(ActivityResult.STATUS_COMPLETE,
      ActivityResult.SUCCESS,
      "eMail Sent",
      null);
  } catch (Exception e) {
    return new ActivityResult(ActivityResult.STATUS_COMPLETE,
      ActivityResult.FAILED,
      "eMail Not Sent",
      null);
  }
}

Registering the JAR and registering the extension in the workflowextensions.xml file is all that is required to make the extension available.

<ACTIVITY ACTIVITYID="sendMail" LIMIT="600000">
  <IMPLEMENTATION_TYPE>
    <APPLICATION CLASS_NAME="com.sswann.sendMail" METHOD_NAME="sendMail" />
  </IMPLEMENTATION_TYPE>
  <TRANSITION_RESTRICTION SPLIT="XOR" />
  <PARAMETERS>
    <IN_PARAMETERS PARAM_ID="recipient" TYPE="String" />
    <IN_PARAMETERS PARAM_ID="subject" TYPE="String" />
    <IN_PARAMETERS PARAM_ID="body" TYPE="String" />
  </PARAMETERS>
</ACTIVITY>


From here, it's merely a matter of constructing your relevant data and handling the activity.resultSummary correctly in your subsequent nodes.

Previously, I stated that workflow extensions should be created when you find you are repeating Javascript over and over again. If you need to check the status of an account owner before invoking an account operation, that would sound like a great candidate for creating a workflow extension and having a solid reusable component. A list of useful extensions might include:
  • Check Account Already Exists
  • Check Owner Status
  • Check Manager Status
  • Read/Update LDAP Object (not an identity or account)
  • Read/Update Database Object
  • Read/Update Message on ESB (MQ)
  • Call Web Service
  • Create Helpdesk Ticket/Send Alert

Have you any good candidates for an extension?

Thursday, September 26, 2013

ITIM Best Practices For Workflow Design

It sounds rather arrogant to call this blog entry "Best Practices" when it is merely my meandering thoughts that I'm about to spew forth. But a number of experiences of other people's work recently has almost moved me to tears.

So here is my list of "best practices".

Workflow Start Nodes

The Start Node (and the End Node for that matter) is not somewhere that code should be placed. Code can be placed in these nodes, of course. But it shouldn't ever be placed in here. For example, how could I know that the following Workflow has been customised:



If you have code that needs to be run as soon as the workflow starts, place a Script Node immediately after the Start Node and name it appropriately. This is MUCH better:



Script Node Size

If I open a Script Node and find that there are 1,000 lines of code in there, I will cry. If you have 1,000 lines of code you are probably doing something wrong. I would much rather see multiple Script Nodes with a sensible name describing their function laid out in an organised manner that gives me a good visual representation of the process rather than having to wade through hundreds or thousands of lines of code.

Workflow Extensions

If you have written some Javascript that looks cool and funky and re-usable, then make it cool and funky and re-usable by creating a Workflow Extension. Also, feel free to give extensions back to the community! (I shall publish some of my favourites soon!)

Hardcoding!

If I see a hardcoded erglobalid reference in a Script Node, I will, in all possibility, hunt the developer down and do very un-Tivolian things to him or her. Their assumption that their code will work when promoted through various environments is very flawed and they are being lazy. Do Not Hardcode!

Commenting & Logging
You might think your code is readable, but the chances are that it could still do with some comments here and there. Even if the code is understandable, the reasoning behind performing the function may not be so clear and requirements documents and design documents have a habit of disappearing!

When it comes to logging, log appropriately and update the status of the workflow throughout the workflow process. The following statements are great to see in Script Nodes because we can successfully handle any problems and ensure that we always navigate our way to the End Node.

activity.setResult(activity.SUCCESS, "Attributes Successfully Verified");
activity.setResult(activity.FAILED, "Attribute Verification Failed due to " + errMsg);

And Finally

The chances are that someone will come along after you have done all your hard work and they will look at your workflow. Do you want them to cry? Or do you want them to be delighted in what they have seen? Make sure you delight people!

Thursday, May 24, 2012

Re-Routing ITIM Approvals

The ITIM workflow engine can be really quite powerful once you have mastered it but getting the very best of it can require some out-of-the-box thinking.

Take, for example, the ability to re-route approvals. Why would you ever want to do that, you might ask. Well, we might provide a mechanism for an end user to select a particular user population for approving requests which would, of course, mean that the end user will habitually select the wrong user population!

Let's take an example:

Massive Corporation provides a suite of services which are accessed by staff and 3rd parties. Of the 3rd parties, many are users requiring read/write access to data but some are journalists who require access to press releases. Read/Write users should be approved by Read/Write approvers; Journalists should be approved by the Press Release approvers.

Now, let's consider that a journalist attempts to register for access but accidentally selects the Read/Write access. When his request is routed to the Read/Write approvers, the approvers have the ability to either Approve or Reject. What if they wanted to route the request to the Press Release approvers instead?

One solution to this problem might be to embed the approval process in a loop and capture rejections within the loop with an "Are You Sure?" RFI node:
So what's going on here? The Approval node should be understood as should the connection from that node to the script marked APPROVED. This route assumes that approval has been granted.

The rejection route, however, connects to an RFI node. The RFI node could be configured to route the request to some "central" team who has responsibility for validating rejections and routing requests appropriately. The RFI could ask this team to confirm the rejection or select a new approver and, in effect, try the process again.

Rejection confirmation would cause the LOOP to exit, but the selection of a new approver would cause us to go around the LOOP once more. And we can LOOP ad infinitum, if required.

Of course, an RFI is a Request For Information which requires data attributes to be populated on the entity object for the workflow. We would have to attach 2 new attributes to the entity:
  • reject
  • approver

Reject could be a boolean attribute wherease approver is a container for a role within the system - a role which can be selected using a Search Match.

Now, we have a simple and robust mechanism for re-routing approvals following a rejection. With an RFI node after a rejection, we can even capture Reject Reasons and "sanitise" them just in case we publish the reason back to the user!

Of course, this is just one solution to the problem. There are others. How would you tackle the problem?