Monday, February 20, 2012

Copy, Paste And ITIM Workflows

The astute amongst you will have seen that developing ITIM Workflows got a little trickier about a year or so ago when copying and pasting into and out of the script editor just stopped working.

Of course, this isn't an ITIM issue - but rather a "security" loophole plugging issue given to use by the powers that be at Java HQ.

The very astute amonst you will know how to get around this hassle and re-enable clipboard access, but for the rest of you, read on.

Shut-down your browser and any Java based applications. Open your favourite editor - if you are a Windows user, you may want to run it as Administrator! Locate your java.policy file which you may find under {JAVA_HOME}\lib\security and add the following line within the grant { } section:

permission java.awt.AWTPermission "accessClipboard";

Restart your browser and you ought to have full copy/paste functionality once again.

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!