In the introduction to this series, SAP HR CMP Integration Driver I discussed the plan of working through the SAP HR driver that comes with the Compliance Management Platform (CMP) to give a better understanding of its inner workings.
You can read more about the new family of SAP drivers that were released with Identity Manager 3.6 and the Compliance Management Platform in this article on the SAP family of drivers:
As this series develops, I will update the links to the rest of the series here:
The plan is to try and get more articles of this nature, which walk through a default driver configuration, explaining WHAT is going on, and when possible WHY it is done that way, in order to make troubleshooting and modifications easier and safer. If you do not know WHY something is being done, it is often hard to work with it.
There are all sorts of interesting little tidbits scattered throughout the various driver configurations that are of interest, and it would be great to have them all in one location as a reference.
Thus I started this Wiki page: http://wiki.novell.com/index.php/Detailed_driver_walk_through_collection to try and pull it all together.
If you have the time, consider looking at a driver configuration you are very familiar with and try writing up a channel (Publisher or Subscriber), a policy set (Say the Publisher Event Transform, or the Subscriber Command Transform, or whatever tickles your fancy), or if you can, the entire driver.
The more we get written, the better it is for everyone. This is also of interest for the older and newer driver configurations, as they change from version to version, and it is important to be able to notice the differences between the two, if we are to ever have a hope of doing a meaningful upgrade.
The hope is to get as much content, even duplicate content, as different perspectives are of interest, together to make it better for everyone.
A quick recap of the SAP HR driver then. The current shipping driver handles the relationships between Organizations, Positions, Jobs, and Persons in SAP's HR module in a somewhat simple fashion, and if your SAP OM (Organizational Management) module is used in any a somewhat complex fashion, then the driver may have problems with it.
This was recognized, and for backwards compatibility reasons, the Novell Identity Manager 3.6 product comes with two different versions of the SAP HR driver. There is the previous version, updated for Identity Manager 3.6 and there is the version called the CMP SAP HR driver.
This second driver is the one under discussion, and it requires a second driver to work hand in hand with, the SAP Business Logic driver.
Lets work through the new CMP SAP HR driver first, then on to the SAP Business Logic.
In the first article (SAP HR CMP Integration Driver Walkthrough - Part 1) I discussed the driver configuration settings.
In the second article (SAP HR CMP Integration Driver Walkthrough - Part 2) I discussed the Global Configuration Values.
In the third article (SAP HR CMP Integration Driver Walkthrough - Part 3) I started on the Input transform. and got barely into the Publisher, Event Transform rule set.
In the fourth article (SAP HR CMP Integration Driver Walkthrough - Part 4)I got part way through the Publisher Event transform.
In the fifth article (SAP HR CMP Integration Driver Walkthrough - Part 5) I finally finished the Publisher Event Transform.
In the sixth article (SAP HR CMP Integration Driver Walkthrough - Part 6) I made it through the Match and Create rules.
In the seventh article (SAP HR CMP Integration Driver Walkthrough - Part 7) I made it through the Placement rule, which was trickier than expected.
Lets continue then from where I left off, having made it into the Publishers Command Transform rule set.
only User ADD
Make sure this is only for User objects, and <add> events.
check for drv.proc.log enabled
This checks if logging is enabled, and logs that we are about to filter events to make sure the validity is correct.
strip out future and historic events
Here is an example of the driver coders using a harder way than in probably neccessary, when a DirXML Script token exists for the task.
They set the variable now to time in seconds (aka CTIME) but use an ECMA Script call, when it would have been just as easy to use the Time() token, which is much more readable. Now I suspect they do it that way, since they use the ECMA getSeconds() functions in the XPATH for the next two items, and so for consistency stuck with one approach. Nonetheless, I think it might have been nicer to do it the readable way.
Now here we have some fun! This really shows the power of XPATH. The driver uses a Strip by XPATH expression, with an XPATH select string of:
add-attr/value[(es:getSeconds(substring-before(@timestamp, '-'), 'yyyyMMdd') > $now) and (string-length(substring-before(@timestamp, '-')) > 0) and (../@attr-name!='DirXML-sapPID') and (../@attr-name!='DirXML-sapPActions')]
What this says is, looking at the current document, (since no other context is specified in the XPATH, like $VARNAME/ or the like) and for all add-attr/value nodes... And now is where we see the power of predicates!
The predicate is the stuff in the  brackets. So lets call out that segment:
[(es:getSeconds(substring-before(@timestamp, '-'), 'yyyyMMdd') > $now) and (string-length(substring-before(@timestamp, '-')) > 0) and (../@attr-name!='DirXML-sapPID') and (../@attr-name!='DirXML-sapPActions')]
Still a mouth full. Ok, lets read that closely and realize there are really four AND clauses. Lets try and represent that better as:
(es:getSeconds(substring-before(@timestamp, '-'), 'yyyyMMdd') > $now)
and (string-length(substring-before(@timestamp, '-')) > 0)
Ok, that is more readable. Lets try and rip that apart now.
es:getSeconds as noted above is basically a way to call Convert Time () done in ECMA Script. Ok, so what are we converting? Well lets break that out and it is:
substring-before(@timestamp, '-'), 'yyyyMMdd')
As noted earlier in previous articles in this series every attribute coming from SAP HR has a @timestamp attribute that looks like:
<value seqnr="000" timestamp="20040901-99991231">Compounding Operator III</value>
The timestamp XML attribute is BEGDA-ENDDA from SAP HR, which is Begin Date in YYYYMMDD and End date in the same format. so we are using subtring-before() from the XPATH function set, and get the value before the dash (-) to get the 20040901 and then that gets converted to CTIME (seconds since 1970) and then the XPATH does a test, of is this value, greater than $now. $now is the variable for the current time in CTIME. Thus if it is true, thats a Future dated event. By definition.
Second line is confirm it is greater than 0. I am not sure why this is needed, since now is always about a billion of more seconds since 1970...
Finally the double clause is to check that the actual attribute being looked at, is not DirXML-sapID nor DirXML-sapActions. I think that is because ID's are really useful even if they are future dated. This is a real case, where a user is being hired and entered today. but will not start week for two weeks.
It makes life a lot easier if we create them with the PERNUM now, but disabled, and later add the rest of the data on them.
What this strip by XPATH expression ends up doing is really cool and most importantly, FAST, is look at the entire current XML XDS document for the user, probably with 25 or more attributes, and any of the them in the future, and meet the requirements described above, get removed. Which is a big time savings, compared to how you would do this with a for-each loop, and test each attribute in turn.
Another way of saying that, is the XPATH operates on the entire node set at once, instead of looking at each element separately. This becomes very much more efficient. I noticed this in an example of strip by XPATH that I once ran into, that would remove hundreds of unwanted nodes from a node set variable, in just a few milliseconds leaving me with a much smaller node set to work through in a slower for each approach. You can read more about that specific example in this article:
Cool tricks using XPATH on nodesets
Next up is do the same thing, but for the old stuff (past date).
Lets get through this quickly by just breaking up the predicates in the same way as above to make it more readable:
add-attr/value[(es:getSeconds(substring-after(@timestamp, '-'), 'yyyyMMdd') < $now) and (string-length(substring-before(@timestamp, '-')) > 0) and (../@attr-name!='DirXML-sapPID') and (../@attr-name!='DirXML-sapPActions')]
(es:getSeconds(substring-after(@timestamp, '-'), 'yyyyMMdd') < $now)
and (string-length(substring-before(@timestamp, '-')) > 0)
Same basic tests, just the first one tests for less than (<) $now, instead of greater than. Therefore, that would be past events. Same test for greater than zero. Same exclusions for two attributes (!=) DirXML-sapID and DirXML-sapActions.
Now comes the question, why the exclusions for the two attributes, DirXML-sapID and DirXML-sapActions? Well if you look at the comments on this particular rule, there is a note, (yay!) that says: changed by hdopp@novell to fix Bug 523509 and if you look in Bugzilla for this bug (https://bugzilla.novell.com/show_bug.cgi?id=523509 ) you can see that there was an issue, that the future and past date stripping, without excluding these two attributes was causing errors on creates. It turns out that the DirXML-sapPID was mandatory, and the DirXML-sapPActions was needed to know what to do about the object, so they modified the driver configuration to exclude these two attributes.
This is a very nice thing Novell has been doing lately, allowing access into Bugzilla. For the eDirectory and Identity Manager product lines at least, most Bugzilla entries are open to view. You do have to be logged in to see most of the bug comments, and some will still remain hidden, specifically when they contain confidential customer information. Often when you submit trace on a bug, there is data in there you really do not want to be seen by everyone, which is pretty fair. Specifically when it is your data that is there. Usually I try to santize the trace before I submit it, but sometimes you do not have enough time, if the issue is pressing enough.
Last rule in the Publisher channel is here! Wow, that was a long ride. The rule name is: Increment DirXML-Other2 (revision counter) by 1 for each modification of DirXML-nwoContent or DirXML-DueDate.
That is actually pretty helpful as a rule name. I still would prefer more commentary, but I will take what I can get.
This rule tests for Work Order objects in the process flow, for which either the DirXML-nwoContent attribute, or the DirXML-DueDate is changing. The DirXML-DueDate tells you that the future date for the event has changed, and the DirXML-nwoContent shows you that the future dated event info, (aka the main payload for the work order) has been updated.
In both those cases, you want to kick up the revision count for the Work Order object. The driver is using the DirXML-Other2 attribute to store the revision count. Work Order objects are sort of loosely defined, in terms of what each attribute should be used for. I happen to disagree with some basic syntax choices. For example, I find the lack of a DN reference attribute quite limiting. What that means is that there is no attribute in the default schema of a DirXML-WorkOder object to store the DN (Distinguished Name) of the target object. If you use a string attribute, as the expectation seems to be, then if the target object is renamed or moved before your Work Order comes due, (DirXML-DueDate) then things get kind of odd, and you have to code something to handle that case. If a DN syntax attribute is used, then there is no need to do any work. However, of course there is a use case for just the opposite, where you want the move or rename event to invalidate the Work Order, in which case a string syntax attribute would make that pretty trivial, since the target object held in the attribute is now invalid, and before you do anything with, a quick test to make sure it exists would be sufficient to handle those cases.
Interestingly enough, there is a minor typo, in the set local variable, that gets the current value of the revision of the Work Order object. The object class is set as DirXML_WorkOrder when it should be DirXML-WorkOrder.
Anyway, it gets the current value, and adds a leading zero, (which is of no consequence if there is a value, but is useful, to initialize an empty value to 0 if there is no value) and then adds a 1 to the value. This way it increments the counter nicely and cleanly, handling the case where there is a value and when there is no value.
On that note, we have finished working through the Publisher channel, and that took more effort that I expected. Next up is to work through the Subscriber channel, which is markedly sparse (phew, save me some effort). Once that is done, it is probably time to start working on the SAP HR Business Logic driver from the CMP. While at BrainShare this year I got to meet Holder Dopp, who is responsible for most of these drivers, and that was a lot of fun.
He demoed version 2 of this configuration, which is pretty much a total re-write, which at some levels makes me wonder if it is worth finishing it up, but since this configuration level is out there already and people are probably using it, I think it is worth finishing it, and when Holger is ready to release the next version, working through that as well. I think examining the differences between the two would also be instructive, as inferring the logic for changing certain things seems as likely to teach important details as anything else I could spend my time working on.