Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. 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, February 09, 2012

Tivoli Directory Integrator and Long Objects

Those of you who use Tivoli Directory Integrator to interface with Tivoli Identity Manager using the ITIM API may have found yourselves wanting to grab the Process ID of requests that you make to ITIM. If so, you may have come across a peculiarity within TDI when it comes to handling Long objects.

Of course, the peculiarity is not limited to those interactions with ITIM - it's just that ITIM returns Process IDs in java.lang.Long format. All handling of java.lang.Long objects should be treated suspiciously.

Take for example the following logic:

var myString = "6746449726097972618";
var myLong = new java.lang.Long(myString);

task.logmsg("INFO", "STRING is: " + myString);
task.logmsg("INFO", "LONG is: " + myLong.longValue);

One might reasonably assume that the resulting log file will display the long number 6746449726097972618 twice. But you would be wrong. In fact, the log will look a lot like this:

08:51:23,047 INFO  - CTGDIS087I Iterating.
08:51:23,047 INFO  - CTGDIS086I No iterator in AssemblyLine, will run single pass only.
08:51:23,047 INFO  - CTGDIS092I Using runtime provided entry as working entry (first pass only).
08:51:23,057 INFO - STRING is: 6746449726097972618
08:51:23,057 INFO - LONG is: 6746449726097972224
08:51:23,057 INFO  - CTGDIS088I Finished iterating.
08:51:23,057 INFO  - CTGDIS100I Printing the Connector statistics.
08:51:23,057 INFO  -  [EmptyScript] Calls: 1
08:51:23,057 INFO  - CTGDIS104I Total: Not used.
08:51:23,057 INFO  - CTGDIS101I Finished printing the Connector statistics.
08:51:23,057 INFO  - CTGDIS080I Terminated successfully (0 errors).

So why the lack of precision when we try to display our Long object? A clue to what is going on here can be found by adding the following line of code:

task.logmsg(myLong.longValue);

Now, our log file looks like this:

08:51:29,237 INFO - STRING is: 6746449726097972618
08:51:29,237 INFO - LONG is: 6746449726097972224
08:51:29,237 INFO  - 6746449726097972618

So, we have now been able to display our Long object correctly. But the only difference was that I passed my Long object as a long object type rather than as a string. ("LONG is: " + myLong.longValue will convert myLong.longValue to a string prior to appending it to the string "LONG is: ")

It would therefore seem that the toString() conversion within Javascript when operated on a Long object is incapable of retaining precision. In fact, there is plenty of documentary evidence out there explaining Javascript's limitations when it comes to java.lang.Long handling. But why did that final task.logmsg(myLong.longValue) statement work?

The reason, is that we are calling a proper Java method at that point and Java is more than capable of handling java.lang.Long objects (as you might expect).

If you really must play with java.lang.Long objects within your script nodes in TDI and you want to write the object to any target, you'll probably be better to have a think about performing a true Java conversion of the object in order to retain precision, like so...

var myConvertedString = new java.lang.String.valueOf(myLong.longValue);

myConvertedString will now contain 6746449726097972618, as expected, and can be displayed quite happily as a result of calling the task.logmsg() method regardless of how you construct the arguments to the method.

NOTE: In the case of playing with the ITIM API, you will have to wrapper tha String.valueOf() method inside a Java class rather than rely on performing this in Javascript. This is because ITIM will return Request objects within which the Process ID can be retrieved using the getID() method. However, Javascript being Javascript means that a non-precise conversion will have already taken place during a getID() call. Wrap it in a Java class to be sure to get the correct string representation of your Process ID!