Novell Identity Manager is a big product with lots of moving parts. It can be quite daunting to get started working with it. Just as bad, the deeper you dig, the more complexity you discover. Now this is not necessarily a bad thing, it is just something you have to deal with. There is a learning curve.
Thus my attempt here to try and lower that curve. First off I have an article with stuff you should start off reading to get over the first hump in the learning curve. If you have not already read this stuff, take a few minutes and do so, it will pay off ten fold as you work through IDM: FAQ: Getting started with IDM, what should you read?
On top of the learning curve, there are some reasonably well known common problems that beginners in the product will run into. I figured that trying to write them down can only help. If nothing else, Google ought to find it, if you search for it.
Thus I started this series, with the first article that you can read here: Common Mistakes Newcomers to IDM Make – Part 1
In that article I covered the concepts:
In the second article, Common Mistakes Newcomers to IDM Make – Part 2 I covered examples of:
In the third article Common Mistakes Newcomers to IDM Make – Part 3 I covered examples of:
In the fourth article Common Mistakes Newcomers to IDM Make – Part 4 I covered examples of:
In the fifth article Common Mistakes Newcomers to IDM Make – Part 5 I covered examples of:
In the sixth article Common Mistakes Newcomers to IDM Make – Part 6 I covered the issue of:
In the seventh article Common Mistakes Newcomers to IDM Make – Part 7 I covered the issue of:
In the eighth article Common Mistakes Newcomers to IDM Make – Part 8 I talked about some of the consequences of multiple servers in a driver set and some of the issues that come from that decision.
In the ninth article Common Mistakes Newcomers to IDM Make – Part 9 I talked about using Variables in Identity manager, in terms of how to add to them, build nodesets, and long strings.
In this tenth article I would like to discuss how you use the XML building tokens. There is a confusing twist that I think I have a simple example that demonstrates it.
Identity Manager uses an XML dialect called XDS for its communications. There is DirXML Script which is designed to let you manipulate events in XDS. As always you can use any XML processing tools on the events if you want (You can call the from a Java class, or write a class to do what you need). However DirXML Script is surprisingly powerful, and does a pretty good job of what it needs to do.
Originally when IDM was still called DirXML, XSLT was the only option, but with the release of NSure Identity Manager 2.0 we got DirXML Script and it has been getting better ever since.
I had asked a question in an article, where MUST you use XSLT instead of DirXML Script in Identity Manager. Open Call: What Can You Do in XSLT that You Cannot Do in DirXML Script?
The core limitation of DirXML Script is that it wants to work on an XDS document, which means it has to have a <nds> opening tag, followed by an <input> or <output> tag.
Where this matters is in the case of the SOAP driver, where there is an option for the shim. It can send the SOAP envelope as the events parents node, or it can wrap it inside an XDS header, and then DirXML Script (sometimes referred to as Policy) can work with it. This turns out to be very handy since you can then do SOAP drivers without any XSLT.
The other common driver to need XSLT is the Delimited Text driver, and that one, alas does NOT wrap the input document, which is a shame. I have an enhancement request submitted to add this support. If they were to add that, then there would be no need to use XSLT you could just address the event document in Policy.
At least one place XSLT does excel is in building arbitrary XML documents as a result. That is, building a SOAP document to send perhaps, or maybe a custom XML node set your application is expecting.
Well it turns out that the DirXML Script language has sufficient tokens to do this without too much trouble as well. It is just somewhat less readable. You can see some practical examples in my series on building a SOAP driver to talk to Salesforce.com:
There are several tokens of interest.
Using these tokens you need to be able to specify target expressions in XPATH. Alas the Novell provided documentation on XPATH is weak to nonexistent. I have tried to help out with a series of XPATH articles, I hope these are helpful to you:
XPATH Cool tips:
This is the basic token, used to add a XML node (element). You can target the current event using XPATH, or a node set local variable. That is you could build your entire XML in a node set variable, and then use Clone by XPATH to copy it into the current event, or elsewhere.
There are all sorts of fun ways to use this, and if you read my series on the Salesforce.com driver, you can see how I build SOAP documents using it.
An example might look like this:
<do-append-xml-element expression="$XML-TEXT/modify" name="modify-attr"/>
The expression is the target where the node shall be placed, and the name, is the name of the node to be added. This will add a <modify-attr> node, into a local variable XML-TEXT under the <modify> node.
Using this we could in memory build the following structure:
<modify> <modify-attr> <add-value> <value></value> </add-value> </modify-attr> <modify>
But that is not yet quite complete.
An XML attribute is the stuff inside a node, things like attr-name=’Surname’ or event-id=’123456′ and so on. Has to be a set, since there must be uniquely named attributes inside any particular node, so if you set the same XML attribute twice, the last one wins.
An example of this would look like this:
<do-set-xml-attr expression="$XML-TEXT/modify/modify-attr" name="attr-name"> <arg-string> <token-text xml:space="preserve">MyAttribute</token-text> </arg-string> </do-set-xml-attr>
Expression is again the target and this one is aiming at the modify-attr node, under the modify node, in the node set local variable XML-TEXT and adding the attr-name attribute with the value of MyAttribute.
Now if you wanted to address the current event document, your XPATH expression for the target would probably look more like modify-attr[@SomePredicate] since the current context is the current event, the <modify> node and your XPATH starts from that base context. As you can see not that much of a difference, but do remember that when using a local variable, you have to start all the way from the top of the XML tree, whereas in a current event the <nds>, <input>, <output> nodes are all sort of ignored.
Thus we could build a document that might look more complete now, like this:
<modify> <modify-attr attr-name='MyAttribute'> <add-value> <value type='string></value> </add-value> </modify-attr> <modify>
So far we have the ability to add an XML element. That lets us build the document, as shown just above, but how do we stuff text in between nodes, like between the <value></value> nodes?
Well that’s what the Append XML text token is meant to do.
An example might be:
<do-append-xml-text expression="$XML-TEXT/modify/modify-attr/add-value/value"> <arg-string> <token-local-variable name="current-node"/> </arg-string> </do-append-xml-text>
Here the expression is used to identify the <value> node, under the <add-value>, under the <modify-attr> node, all of which is contained in the <modify> node in the XML-TEXT node set variable. Then the string value is provided to insert into that node. You can use all the usual tools in Argument Builder to build the string, so the options are wide open.
This would let you finish that example document up to look more like:
<modify> <modify-attr attr-name='MyAttribute'> <add-value> <value type='string>SomeValue</value> </add-value> </modify-attr> <modify>
While technically not directly related to building a new XML document, the ability to clone by XPATH means you can specify an XPATH expression to copy a snippet of existing XML and paste it into a location specified by another XPATH expression.
Thus you could clone by XPATH my local variable XML-TEXT that is a nodeset into the current event document. Or the other way around (Copy part of the current event document into a local variable), and then use that as well.
I have seen this is some drivers, where data is written to the <operation-data> node, which is technically where the operation properties go, except they really go as XML attributes of the operation-data node. The password sync policies interestingly enough actually build some XML elements underneath it.
If you are interested in what and how the Password Sync rules use this operation-data, you can read my series on how they work here:
But any data in the <operation-data> node will be removed as the engine sends it to the shim on the Subscriber channel (since the shim has no idea what to do with it, usually) and then when the event returns back out of the shim, perhaps as a <status> event, the engine will return the operation data. This is one way to carry information through the shim.
Perhaps you want to carry some XML information through the shim, well you could copy your XML into the operation-data node using clone by XPATHa and then either use it directly, or copy it back out again on the other side of the shim.
Like Clone by XPATH this too is not really directly about building the document, though this is more of a surgical tool to clean up if you make a mess, or perhaps if you need to copy something and then clean it up. The XPATH you apply, is to specify what to remove.
Very useful tool.
Now on top of all that, there is a very important and very confusing twist you need. That is a predicate, usually using the last() function to be sure you are targeting the correct node.
The most common way I use these tokens, is inside a for each loop, where I loop over say a list of values, and I build a <modify-attr> node for each value. The current-node say becomes the attr-name XML attribute, and then somehow I get a value for it.
But here is the thing. Using the examples I showed above, (kept simple for simplicity’s sake) will not work. That is, if you are going to loop three times, and use an append XML element as in my example above, but say for the value node, instead of the modify-attr node, something like this:
<do-append-xml-element expression="$XML-TEXT/modify/modify-attr" name="value"/>
There is a problem with the XPATH expression. It is not very specific, in fact you will end up with three value nodes under the first modify-attr, two under the second, and one under the third.
Yes I know that I should be talking about the <add-value> node, with <value> under it, but for simplicity work with my example please.
This is because the first time you loop, the first modify-attr node will get value node added. So far so good. Second time through the loop, you know have two <modify-attr> nodes, and EACH one will get another <value> node added, since both are valid targets of that XPATH. So the first modify-attr has two value nodes, and the second has one.
On the third pass through, you add to all three <modify-attr> nodes, a <value> node. So now the first has three, the second has two, and the final one has just one <value> node.
What you should do is scope your XPATH down. Now I usually just use a predicate of last() so that my target is the last <modify-attr> node. Therefore my Append XML element token usage might look more like this instead:
<do-append-xml-element expression="$XML-TEXT/modify/modify-attr[last()]" name="value"/>
And my Set XML Attribute would also use a predicate of last() as well.
However, let me expand that back to a more proper real world example, where it is modify/modify-attr/add-attr/value as the structure and note that in fact, it is not enough to just put a predicate on the add-value part of the XPATH but also on the modify-attr. Like so:
<do-append-xml-element expression="$XML-TEXT/modify/modify-attr[last()]/add-value[last()]" name="value"/>
If you instead did just the add-value[last()] like so:
<do-append-xml-element expression="$XML-TEXT/modify/modify-attr/add-value[last()]" name="value"/>
then you would still double it up as it would apply to every modify-attr node, but only the last add-value node underneath it.
I decided this was sufficiently complicated to explain, but to me is very obvious when you see it in action. So I have a sample rule below shown that I think illustrates it nicely.
Just paste the entire rule into the XML view of a Policy somewhere in Designer. Now disable any other rules so it is simpler to see the output. Then use Simulator, to run the rule. The Policy object needs to be linked into somewhere in a driver so Simulator can guess at the context you are running it in, thus you can use any other policy object you have, just disable all the other rules for the moment.
Now inside there are two for each loops that loop over a node set of One, Two, Three that I made up for simplicity.
This will try and build a simple modify document in a variable, and trace out the result for you.
Notice one for-each is disabled, one is active. Swap the two apart. Keep one active, one disabled at a time and look at the different outputs you get. You will see it right away I suspect.
This also should show you a couple of tricks.
Anyway, I would suggest you try it in Designer’s Simulator and see what you think.
I even have a nice article on using Simulator if you would like to get started with that: Using Simulator in Designer
I would be curious to hear feedback to know if this example is actually helpful, or still confusing. I will admit the first time I saw the last() notation in XPATH I did not understand why, (It was the Notes driver, and Perry Nufer made a valiant effort to explain it, but I did not entirely get it. The trick he came up with that made me understand it was to modify the XPATH to not have it and see the results go all goofy).
The Set XML attribute is the sneakiest to understand, as basically all of them get set to the last value, so it is not as obvious as the extra nodes being added. However, it is the same principle.
<rule> <description>Buildnodeset using a loop and last()</description> <conditions> <and/> </conditions> <actions> <do-set-local-variable name="XML-TEXT" scope="policy"> <arg-node-set> <token-xml-parse> <token-text xml:space="preserve"><modify/></token-text> </token-xml-parse> </arg-node-set> </do-set-local-variable> <do-for-each disabled="true"> <arg-node-set> <token-text xml:space="preserve">One</token-text> <token-text xml:space="preserve">Two</token-text> <token-text xml:space="preserve">Three</token-text> </arg-node-set> <arg-actions> <do-append-xml-element expression="$XML-TEXT/modify" name="modify-attr"/> <do-append-xml-element expression="$XML-TEXT/modify/modify-attr" name="add-value"/> <do-append-xml-element expression="$XML-TEXT/modify/modify-attr/add-value" name="value"/> <do-append-xml-text expression="$XML-TEXT/modify/modify-attr/add-value/value"> <arg-string> <token-local-variable name="current-node"/> </arg-string> </do-append-xml-text> </arg-actions> </do-for-each> <do-for-each> <arg-node-set> <token-text xml:space="preserve">One</token-text> <token-text xml:space="preserve">Two</token-text> <token-text xml:space="preserve">Three</token-text> </arg-node-set> <arg-actions> <do-append-xml-element expression="$XML-TEXT/modify" name="modify-attr"/> <do-append-xml-element expression="$XML-TEXT/modify/modify-attr[last()]" name="add-value"/> <do-append-xml-element expression="$XML-TEXT/modify/modify-attr[last()]/add-value[last()]" name="value"/> <do-append-xml-text expression="$XML-TEXT/modify/modify-attr[last()]/add-value[last()]/value[last()]"> <arg-string> <token-local-variable name="current-node"/> </arg-string> </do-append-xml-text> </arg-actions> </do-for-each> <do-trace-message> <arg-string> <token-xml-serialize> <token-local-variable name="XML-TEXT"/> </token-xml-serialize> </arg-string> </do-trace-message> </actions> </rule>
Disclaimer: As with everything else at NetIQ Cool Solutions, this content is definitely not supported by NetIQ, so Customer Support will not be able to help you if it has any adverse effect on your environment. It just worked for at least one person, and perhaps it will be useful for you too. Be sure to test in a non-production environment.