Novell Home

General-Purpose Relational Integrity Rules for IDM

Novell Cool Solutions: AppNote
By Rob Schneider

Digg This - Slashdot This

Posted: 21 Nov 2007
 

Introduction
    The Challenge
Use Case Example
Issue I - User Gets a New Job Code
    Part A: Setting the new Title Attribute
    Part B: Establishing the User/Job Relationship
Issue II: Job Object Gets Relevant Information Updated
Conclusion

Introduction

I often create multiple custom classes to handle entities not found in the base eDirectory schema. In most cases, these classes exist as relational tables in a database somewhere, but I need to bring them into eDirectory as objects. The relational database maintains pointers to lookup tables, which aren't naturally maintained in eDirectory. Overcoming this discrepancy between a relational database and an object-oriented directory is a common chore, and the examples here can be reused on multiple similar situations.

The Challenge

The challenge in working with an SQL DBA/Database is maintaining relationships between objects, without writing grossly complex triggers that are not in the interest of the DBA or his/her database. So, I take the raw data to form relationships from the DB and sync it to eDirectory.

However, unlike Group membership, or Manager/report relationships, iManager and Console1 are not built to automatically manage the referential integrity of my raw data. Therefore, we must take care of it ourselves. I have found it useful to maintain relationships similar to "Manager/Direct Report" in eDirectory. I do this by treating lookup tables in the SQL DB as a class of objects and by synchronizing multiple classes through the driver, rather than by trying to stuff everything into the user record - which often doesn't map anyway.

Use Case Example

Let's consider an example. In our HR SQL database, every user has a job code, reflected in the DB's User table. However, the job details are stored on a JOB lookup table, keyed by the jobCode - including things like Description, Title, Cost Center #, Owner, Manager, etc. So when I synchronize just the user class to eDirectory, I am missing useful information.

I can TRY to stuff relevant information from the JOB table-lookup tables into my intermediate USR table, but suffice it to say that the idiosyncrasies of applications may make this less simple or effective than you might think. At the very least, it requires a lot of triggers. At the worst, it just won't work.

So I create a custom Effective Class for Job objects (and other lookup tables that represent entities in my company) and the records stored in the lookup table, and I synchronize that to eDirectory.

I also maintain a multi-valued attribute on the Job objects (similar to Direct Reports) that retains a list of the DN's of all current incumbents for each job. Each Job object becomes almost like a group, keeping track of all current holders of each title.

So, I synchronize a User class and a Job class. Then, in the driver policy, I manage the relationships as follows:

Issue I: Did a user get a new job code? If Yes,

1) Look up the Description from the job object with the new code as its CN and populate the User's Title. (Add other relevant attributes as desired.)

2) Add user DN as "occupant" of the job code.

3) Remove the user DN as the occupant of the former job code (if one is being removed).

But that's only half the battle. When relevant information on a Job object changes, such as Title, the company would like all incumbents' job titles to reflect this change immediately.

Issue II: Did a job object have relevant information updated? If Yes,

1) Look up the list of all job occupants.

2) Modify the changed value for each user.

Here's the code for these two scenarios - modify to fit your infrastructure.

Issue I - User Gets a New Job Code

Part A: Setting the new Title Attribute

This rule is on the publisher Command Transform, coming from my HR system.

<rule>
  <description>User:  jobCode changing, Modify Title to Reflect new Job</description>
  <comment xml:space="preserve">The user's "primary" jobCode is changing.  
Set the Title Value on the User to match the job-code now occupied..</comment>
  <conditions>
    <and>
      <if-class-name mode="nocase" op="equal">User</if-class-name>
      <if-op-attr name="jobCode" op="changing"/>
    </and>
  </conditions>
  <actions>
    <do-set-local-variable name="jcNode" scope="policy">
      <arg-node-set>
        <token-query class-name="jobClassObject" scope="subordinates">
          <arg-dn>
            <token-text xml:space="preserve">my\jobobject\container</token-text>
          </arg-dn>
          <arg-match-attr name="jobCode"/>
          <arg-string>
            <token-text xml:space="preserve">jobCodeDescription</token-text>
          </arg-string>
        </token-query>
      </arg-node-set>
    </do-set-local-variable>
    <do-set-local-variable name="jcText" scope="policy">
      <arg-string>
        <token-xpath expression="$jcNode/attr[@attr-name='jobCodeDescription']/value"/>
      </arg-string>
    </do-set-local-variable>
    <do-set-dest-attr-value name="Title">
      <arg-value>
        <token-local-variable name="jcText"/>
      </arg-value>
    </do-set-dest-attr-value>
  </actions>
</rule>

Part B: Establishing the User/Job Relationship

This rule establishes the relationship of the user's DN to the Job Object's "jobOccupants" multi-valued DN attribute.

<rule>
  <description>User's jobCode Changing: Clear jobOccupants value from former Job held</description>
  <conditions>
    <and>
      <if-op-attr name="jobCode" op="changing"/>
      <if-dest-attr name="Job" op="available"/>
    </and>
  </conditions>
  <actions>
    <do-remove-dest-attr-value direct="true" name="jobOccupants">
      <arg-dn>
        <token-dest-attr name="Job"/>
      </arg-dn>
      <arg-value type="string">
        <token-dest-dn/>
      </arg-value>
    </do-remove-dest-attr-value>
  </actions>
</rule>

<rule>
  <description>jobCode Changing: Modify Relations between Job and its Occupants</description>
  <comment xml:space="preserve">Set new Job DN on the User (Single Valued DN Attribute in this sample)
Add new jobOccupants value on the Job Object (multi-valued DN attribute in this sample) </comment>
  <conditions>
    <and>
      <if-op-attr name="jobCode" op="available"/>
    </and>
  </conditions>
  <actions>
    <do-for-each>
      <arg-node-set>
        <token-query class-name="jobClassObject" datastore="dest" max-result-count="50">
          <arg-dn>
            <token-text xml:space="preserve">MyOrg\myOU</token-text>
          </arg-dn>
          <arg-match-attr name="jobCode"/>
        </token-query>
      </arg-node-set>
      <arg-actions>
        <do-set-local-variable name="dn" scope="policy">
          <arg-string>
            <token-xpath expression="$current-node/@src-dn"/>
          </arg-string>
        </do-set-local-variable>
        <do-set-dest-attr-value name="Job">
          <arg-value>
            <token-local-variable name="dn"/>
          </arg-value>
        </do-set-dest-attr-value>
        <do-add-dest-attr-value class-name="jobClassObject" name="jobOccupants" when="after">
          <arg-dn>
            <token-local-variable name="dn"/>
          </arg-dn>
          <arg-value type="dn">
            <token-dest-dn/>
          </arg-value>
        </do-add-dest-attr-value>
      </arg-actions>
    </do-for-each>
  </actions>
</rule>

Issue II: Job Object Gets Relevant Information Updated

This is also on the Publisher Command Transform.

<rule>
    <description>JOB:  If Job Code Description changing, update all incumbents' Title</description>
    <comment xml:space="preserve">If the Job Code Description changes on any Job object, this rule will update the Title attribute on all Users who "occupy" this job."</comment>
    <conditions>
      <and>
        <if-class-name mode="nocase" op="equal">MyCustomJob</if-class-name>
        <if-operation mode="case" op="equal">modify</if-operation>
        <if-xpath op="not-true">@from-merge</if-xpath>
        <if-op-attr name="MyCustomJobCodeDescription" op="changing"/>
      </and>
    </conditions>
    <actions>
      <do-set-local-variable name="jobHolders" scope="policy">
        <arg-node-set>
          <token-query class-name="User">
            <arg-dn>
              <token-text xml:space="preserve">myOrg\myOU\myUserOU</token-text>
            </arg-dn>
            <arg-match-attr name="jobCode">
              <arg-value type="string">
                <token-dest-name/>
              </arg-value>
            </arg-match-attr>
          </token-query>
        </arg-node-set>
      </do-set-local-variable>
      <do-for-each>
        <arg-node-set>
          <token-local-variable name="jobHolders"/>
        </arg-node-set>
        <arg-actions>
          <do-set-local-variable name="jobHolderDN" scope="policy">
            <arg-string>
              <token-xpath expression="$current-node/@src-dn"/>
            </arg-string>
          </do-set-local-variable>
          <do-set-dest-attr-value class-name="User" direct="true" name="Title">
            <arg-dn>
              <token-local-variable name="jobHolderDN"/>
            </arg-dn>
            <arg-value>
              <token-op-attr name="MyCustomJobCodeDescription"/>
            </arg-value>
          </do-set-dest-attr-value>
        </arg-actions>
      </do-for-each>
    </actions>
  </rule>

Conclusion

You should be able to adapt the code here to serve just about any relationship. With a little work, you could even manage the potential case that the values in question might be edited on either of the related objects.


Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com

© 2014 Novell