Walking through the Oracle EBS HR driver - Part 3

0 Likes
over 6 years ago
I had noticed the Oracle EBS drivers get added to Designer a few patches ago, but never really had much of a chance to look at them. As I have been doing in my driver walkthrough series, I decided to do the Oracle eBusiness HR driver next.

In the first article I made it through the configuration, GCVs, and the started working through the Subscriber channel.

In the second article I finished the Matching policy in the Subscriber channel and got into the Command Transform.

In this article I will continue through the Command Transform.

The Subscriber Command Transformation Policy Set has two policy objects, the first of which I covered in the preceding article.


  • NOVLORAHENT-sub-ctp-EntitlementsImpl

  • NOVLORAHDCFG-sub-ctp-BlockAddAndDelete



The remaining policy is:

NOVLORAHDCFG-sub-ctp-BlockAddAndDelete

There are two rules in this policy.

  • Block add operation if connected system is authoritative source

  • Block delete operation if connected system is authoritative source



From the name it is pretty clear that this rule is meant to control whether adds or deletes are allowed.

Both the rules are basically the same. If the GCV drv.publisher.auth is true, that the Oracle EBS HR system is authoritative, then Adds and Deletes should be blocked. This is done in two rules, that differ only in the If Operation token value. The first blocks adds, so the condition is If Operation equal add. The second blocks Deletes so the condition is If Operation equal delete.

This could have been done more neatly using Condition blocks, or even a simple Regex compare. That is, one rule, still checking the GCV if true, but either using a Condition Group, so that If operation equal add, or If Operation equal delete, AND the GCV is true. Or else simply doing a single If Operation equal, but instead of a Case Insensitive compare, chose Regular Expression, and a value of add|delete which would work.

A minor quibble, could do it any of the three ways with no issue.

Now the bigger question is, why are we blocking deletes and add events here? Isn't that what the Event Transform policy set is meant to handle? In fact, we do veto Move and Rename in the Event Transform already.

It seems to me Deletes should be handled in the Event Transform.

The Adds are slightly trickier, since a modify of a non-associated object will try to match, which we want, and then try to create, and finally let it through. Thus a modify and an add need to get through the Event Transform, and once they get to the Command Transform, then we can decide to veto Adds. A sync or migrate will get this far as well probably as an add, and be handled, but you won't get a delete that way.

I am not entirely sure why they chose to handle deletes here, but it should work.

That finishes up the Command Transform policy set, on to the OUtput Transform.

Output Transform Policy Set



There are four policies in this policy set, and lets start working through them.


  • NOVLORAHENT-otp-EntitlementsImpl

  • NOVLEBSMSI-otp-queryConvertForDatacollection

  • NOVLORAHDCFG-otp-ConvertTime

  • NOVLORAHATRK-otp-Subscribe



NOVLORAHENT-otp-EntitlementsImpl

There is a single rule "Intercept outbound queries for oracleEBSAccount", and this is the common transform for one of the Data Collection processes. It seems like the DCS driver will inject a query into each driver, and if the shim cannot service the query, then the policies detect the queries and returns a basic response. You can read about how you can inject an event into another driver in this article by Alekz.

Query a Connected System from a Driver not Connected to that System

A query, something like this, gets injected, and because the shim will not really return a value for the class,

<nds dtdversion="4.0" ndsversion="8.x">
<source>
<product version="?.?.?.?">DirXML</product>
<contact>Novell, Inc.</contact>
</source>
<input>
<query class-name="oracleEBSAccount">
<read-attr/>
</query>
</input>
</nds>


This is converted into something like this:

<nds dtdversion="4.0" ndsversion="8.x">
<source>
<product version="?.?.?.?">DirXML</product>
<contact>Novell, Inc.</contact>
</source>
<input>
<query event-id="query-driver-ident" scope="entry">
<search-class class-name="__driver_identification_class__"/>
<read-attr/>
</query>
</input>
</nds>


This specific query is unique and every driver responds to it with the version info instance documents that lists the capabilities of the driver. Thus this query is guaranteed to get a response in all cases. The transformation is done via the Append/Add XML attributes/elements tokens with the final step being a driver scoped variable, EmployeeEntitlementQuery being set to true. There will be a rule in the Input Transform that will see the driver identification query test for the local variable (if not set, it is a driver startup event, and skip any processing) and if set, convert it to a form the data collection expects.

NOVLEBSMSI-otp-queryConvertForDatacollection

This policy has two rules.


  • Change the Roles class name

  • Change the Responsibility class name



Change the Roles class name

This rule is looking for query or query-ex operations, using the Regex approach I discussed as possible in the Command Transform, for vetoing add or delete operations. Then it checks for a data-collection-query operation property. I assume that the injected event carries this with it, since I have not seen any rules to process such an event come down this channel so far.

Finally it checks if the class name is ORACLEEBSROLES, if so, it set the class name to ROLESDATAC, and it strips the XPath expression search-class.

What this does is, when you send a query, you actually have the class in two places. First in the <query class-name"MyClass"> and second in a <search-class class-name="MyClass"> and this Strip XPATH is to remove that second item.

Where does the ORACLEEBSROLES value come from? If you think about it, there is a chicken and egg issue of where this comes from, and how does whatever queries for it, know that value? It has to be discovered somehow.

Well this is where some understanding of how User App and RBPM manage roles, resources, and entitlements. I have been meaning to write another article on this topic since it is long and complicated, and worthy of discussion its own with copious trace samples.

But for now, the change in RBPM from 3.60 to 3.70 with the addition of Resources was described here:
Convert Driver Entitlements to New RBPM 3.7 Resource Model

I went on to dissect what was really happening here.

Converting Entitlements to Resources, more details

What it comes down to is there is policy in each driver that maintains a entitlementConfiguration object unique to that driver. It looks at the Entitlements defined on the driver, gets data out of them, writes it to the appropriate place in the XML.

Then User App does a CODE MAP REFRESH which does an LDAP query for all the DirXML-Driver objects that have a entitlementConfiguration object under them. It reads and parses the object so it knows how to generate these queries to send through either the User App driver or the DCS driver.

You see the results when you try to create a Resource in User App, and you select a driver and it shows you the list of entitlements available. It derived them from the results of that query. Thus a driver advertises its available entitlements through that object.

Ok, so where did the specific string ORACLEEBSROLES come from? Well lets track it back, I do not have a working system so I cannot directly see it in a generated entitlementConfiguration object (also, as you will see in moment that wouldn't work anyway) but I can read the rule that generates that object. It is in the Input Transform, named NOVLORAHENT-itp-InitEntitlementConfigurationResource. This is the policy the two articles above discuss how they work. But in this context the key is that the rule loops over the DirXML-Entitlement objects,

The XML for an entitlement looks like:

<entitlement conflict-resolution="union" description="Employee entitlement for Oracle EBS" display-name="Oracle EBS Employee">
<values multi-valued="false">
<query-app>
<query-xml>
<nds dtdversion="2.0">
<input>
<query class-name="oracleEBSAccount" scope="">
<search-class class-name="oracleEBSAccount"/>
<read-attr attr-name="Value"/>
<read-attr attr-name="Description"/>
<read-attr attr-name="DisplayName"/>
</query>
</input>
</nds>
</query-xml>
<result-set>
<display-name>
<token-attr attr-name="DisplayName"/>
</display-name>
<description>
<token-attr attr-name="Description"/>
</description>
<ent-value>
<token-attr attr-name="Value"/>
</ent-value>
</result-set>
</query-app>
</values>
</entitlement>


Hmm, no sign of ORACLEEBSRESP or ORACLEEBSROLES (as the second rule for Roles uses). Darn it, I like being able to understand where stuff comes from. So where else could this be?

I had figured this out the first time I looked at it, then I went off to BrainShare and came back to this article a week later and could not remember. Took me a while to figure it out again.

The answer is simple, but is the result of a mishmash of policies from three drivers, not being completely cleaned up. The Oracle EBS drivers were built as a set of three to handle all the cases, and then reduced to handle just each use case. This means that the TCA and UM drivers handle Role and Responsibility entitlements, in addition to the UserAccount entitlement that HR only handles.

These two strings, for Role and Responsibility are found in the Role and Responsibility entitlements. Of course the HR driver does not have these, so you have to go look in the TCA or UM driver. From the TCA driver, here is an example of the Responsibility entitlement, to compare to the UserAccount entitlement above.

<entitlement conflict-resolution="union" description="Roles in Oracle EBS" display-name="Oracle EBS Roles">
<values multi-valued="true">
<query-app>
<query-xml>
<nds dtdversion="2.0">
<input>
<query class-name="ORACLEEBSROLES" scope="">
<search-class class-name="ORACLEEBSROLES"/>
<read-attr attr-name="Description"/>
<read-attr attr-name="WF_ROLE_NAME"/>
</query>
</input>
</nds>
</query-xml>
<result-set>
<display-name>
<token-src-dn/>
</display-name>
<description>
<token-attr attr-name="Description"/>
</description>
<ent-value>
<token-attr attr-name="WF_ROLE_NAME"/>
</ent-value>
</result-set>
</query-app>
</values>
</entitlement>


You can see that the query class name is ORACLEEBSRESP which is what our policy is modifying to be RESPDATAC.

The EntitlementConfiguration object, created when you first start the driver, and updated if needed on every restart, will have this <query> XML copied into a node, in something that looks like this:

<entitlement-configuration modified="20130417013734">
<entitlements>
<entitlement data-collection="true" dn="CN=Role,CN=EBS-HR,CN=DRIVERSET01,OU=Servers,O=AcmeDev" parameter-format="idm4" resource-mapping="true" role-mapping="true">
<type category="security grouping" id="role" name="role">
<display-name>
<value langCode="en">Role</value>
</display-name>
</type>
<parameters>
<parameter mandatory="true" name="ID" source="read-attr" source-name="WF_ROLE_NAME/>
</parameters>
<entitlement-extensions>
<member-assignment-extensions>
<query-xml>
<read-attr attr-name="USER_DATA"/>
</query-xml>
</member-assignment-extensions>
<query-extensions>
<query-xml>
<operation-data data-collection-query="true"></operation-data>
</query-xml>
</query-extensions>
</entitlement-extensions>
</entitlement>
</entitlements>
</entitlement-configuration>


User App does a CODE MAP REFRESH, reads back this object from all drivers in the driverset. Now it knows for each driver, the names and LDAP DN's of the supported Entitlements. Then it goes and reads each Entitlement object referenced, to get the <query-app> info from the Entitlement example above. That is where the class name of ORACLEEBSROLES is coming from.

You can see all this happen in the User Application trace (depends on your Web Application server platform, JBoss vs WebSphere vs Tomcat (4.5 option) will log to different files. JBoss is usually something like /opt/novell/idm/rbpm/jboss/server/IDMProv/log/server.log whereas WebSphere is a much deeper path very much dependant on where it was installed. It is usually under the Dmgr0 path that has eventually all the children sites, and then finally a logging directory under there. For Tomcat it is much simpler, and just in catalina.out, where ever your Tomcat is logging too).

To see it in trace you need to enable two logging classes:
com.novell.idm.nrf.persist
com.novell.idm.nrf.service

I had some trace examples of this, but do not have them handy, I wish I had saved them in a better format. Be fun to walk through that line by line to show what you should be seeing, and what is broken when you do not, but not today.

When you do, you will see it first read each driver EntitlementConfiguration object which it gets by pre-pending cn=EntitlementConfiguration onto each drivers DN, and then from within, reading the XPATH equivalent of entitlement-configuration/entitlements/entitlement/@dn values and then querying the directory for each of those. Along the way, it can read back the @data-collection, @parameter-format, @resource-mapping, and @role-mapping nodes to know this entitlement is configured.

I do not per se disagree with storing the information in this format, I just think it would have been simpler to extend the DirXML-Entitlement objects XML schema to include this info in each entitlement itself, instead of needing this other object to explain it. It is metadata about how the Entitlement is configured, which seems like the perfect place to define it, would be where the Entitlement is configured, right?

Also, it seems like this is not something that needs to spend this much effort on configuring, it should just have been part of the Entitlement GUI and stored in the XML. So really it is the process that bothers me, not necessarily the construct used directly.

I do wish Packaged drivers would come with a mostly instantiated EntitlementConfiguration object, lacking only the LDAP DN (since of course that will differ in every import case). Mostly because then I would not have to construct one by hand as I did for the example above, when dissecting a driver I do not have a sample system to play with. Maybe I should put out a call for copies of EntitlementConfiguration object samples for all known drivers. That might be useful, when you have an issue in this space, you could then compare yours to a known good example. That might work.

Having said all that, the more interesting question is, if the class needs to be RESPDATAC, why did they not change the Entitlement definition to use that value flat out. If there is a good reason for that, then second why not just map it in the Schema Map. Query events go through the schema map and the class and attribute names get mapped per the definition?

I do not have good answers for that, other than maybe the tables they started developing with (that are handled at install via the PL/SQL scripts) set the initial value and they stuck with it.

Change the Responsibility class name

This rule does the same thing, just swapping the class name from ORACLEEBSRESP to RESPDATAC which is the value found in the Responsibility entitlement object definition.

Well that about wraps up this article. Onwards and upwards, as I will continue through the Output Transform in the next article in this series. Stay tuned, same bat-time, same bat-channel. (I miss Adam West in Batman (Though I know he is the mayor on Family Guy!))

Labels:

How To-Best Practice
Comment List
Anonymous
Related Discussions
Recommended