<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jayway Team Blog &#187; referential integrity</title>
	<atom:link href="http://blog.jayway.com/tag/referential-integrity/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.jayway.com</link>
	<description>Sharing Experience</description>
	<lastBuildDate>Sun, 05 Sep 2010 20:32:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Referential Integrity using Spring LDAP</title>
		<link>http://blog.jayway.com/2009/12/07/referential-integrity-using-spring-ldap/</link>
		<comments>http://blog.jayway.com/2009/12/07/referential-integrity-using-spring-ldap/#comments</comments>
		<pubDate>Mon, 07 Dec 2009 08:40:39 +0000</pubDate>
		<dc:creator>Vlado Palczynski</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[referential integrity]]></category>
		<category><![CDATA[spring]]></category>
		<category><![CDATA[spring ldap]]></category>

		<guid isPermaLink="false">http://blog.jayway.com/?p=2660</guid>
		<description><![CDATA[The directory servers of today are packed with a lot of nice features, one of them being Referential Integrity which performs integrity updates on attributes like member, uniqueMember, owner etc. Simpler put, when an entry updates its distinguished name, all references using the old distinguished name get updated to the new one. However, there can [...]]]></description>
			<content:encoded><![CDATA[<p>The directory servers of today are packed with a lot of nice features, one of them being <em>Referential Integrity</em> which performs integrity updates on attributes like member, uniqueMember, owner etc. Simpler put, when an entry updates its distinguished name, all references using the old distinguished name get updated to the new one.</p>
<p>However, there can be cases where your directory server setup might have to avoid using this feature. In our case we had a multi master environment and the plug-in cannot be enabled on both machines as it would create a circular update loop between the master servers. To have one machine in production with the plug-in wasn't a good choice either as we want the master configurations to be same on both machines and if one master goes down then there is a 50-50 chance that the <em>Referential Integrity</em> goes down with it.</p>
<p>Another reason is that you might not store distinguished names on relations attributes, but values like guid or uid, and then the <em>Referential Integrity</em> won't work.</p>
<p>Still this point to an interesting feature which should be pretty easy to implement in Java using Spring LDAP.</p>
<h3>Scenario 1</h3>
<p>A person who's used as owner in some entries updates his/her uid from <strong>old.uid</strong> to <strong>new.uid</strong>, where uid is a part of the distinguished name. For example, Jane Unmarried changes here name to Jane Doe: "uid=jane.unmarried, dc=jayway, dc=com" -> "uid=jane.doe, dc=jayway, dc=com".<br />
<strong>Feature</strong>: Update all owner references to the new distinguished name.<br />
<strong>Prerequisite</strong>: Single value attribute. The <em>owner</em> attribute should be indexed for best performance.</p>
<p>The <em>owner</em> attribute might be featured in many different objectclasses, so the tiresome way would be to make searches per objectclass and update them one by one. However, we can make use of a nice feature in LDAP: attributes are global and standardized according to an LDAP schema. The <em>owner</em> attribute is of the same type everywhere, so there is no risk of accidentally changing an <em>owner</em> attribute that is used for something else. Thus, a much better way would be to make a more general search:</p>
<pre>
EqualsFilter filter = new EqualsFilter("owner", "uid=old.uid, dc=jayway, dc=com");
</pre>
<p>And what do we want to return? The distinguished name should be sufficient:</p>
<pre>
protected AbstractContextMapper getAbstractMapper() {
        return new AbstractContextMapper() {

            /* Returns the distinguished name of the object it found. */
            protected Object doMapFromContext(DirContextOperations ctx) {
                return ctx.getNameInNamespace();
            }
        };
    }
}
</pre>
<p>This is all the information we need; a list of pointers to all entries in the LDAP structure where there is an owner attribute with the value <em>"uid=old.uid, dc=jayway, dc=com"</em>. We don't care which type of entries were found, as the only thing we're interested in is updating the value of the <em>owner</em> attribute.</p>
<p>Now do the search:</p>
<pre>
List<Name> hits =  ldapTemplate.search(
                 DistinguishedName.EMPTY_PATH,
                 filter.encode(),
                 getAbstractMapper());
</pre>
<p>We need to iterate through the search hits and only update the attribute, not the whole object, as we do not know anything about the object type:</p>
<pre>
for (Name someObjectDn: hits) {
    DirContextOperations context = ldapTemplate.lookupContext(someObjectDn);
    context.setAttributeValue("owner", "uid=new.uid, dc=jayway, dc=com");'

    ldapTemplate.modifyAttributes(context);
}
</pre>
<p>And we're done, the owner references are updated to <em>uid=new.uid, dc=jayway, dc=com</em>.</p>
<p>What if the owner person gets deleted? Well, then the <em>owner</em> values should be removed and all we need to do is replacing this:</p>
<pre>
context.setAttributeValue("owner", "uid=new.uid, dc=jayway, dc=com");
</pre>
<p>with this:</p>
<pre>
context.setAttributeValue("owner", null);
</pre>
<p>and the attribute owner will be removed from all the objects.</p>
<h3>General</h3>
<p>So we see that all we need for these kind of operations are:</p>
<ul>
1. The attribute name<br />
2. The current value<br />
3. The new value, null if to remove the attribute
</ul>
<p>Scenario 1 handles a single value attribute but it shouldn't be any harder with a multivalue attribute. The problem is that it's optional to define in an LDAP Schema whether an attribute is singlevalue or multivalue, so we cannot be certain what kind of attribute we're updating. The easiest way to solve this is to let the method have a boolean parameter for this:</p>
<ul>4. Is multivalue.</ul>
<h3>Scenario 2</h3>
<p>An person updates his/her uid (from <strong>old.uid</strong> to <strong>new.uid</strong>) and uid is a part of the distinguished name.<br />
<strong>Feature</strong>: Update person references in all object classes she is a member of.<br />
<strong>Prerequisite</strong>: Multivalue attribute. The <em>uniqueMember</em> attribute should be indexed for best performance.</p>
<p>The filter is almost the same as above:</p>
<pre>
EqualsFilter filter = new EqualsFilter("uniqueMember", "uid=old.uid, dc=jayway, dc=com");
</pre>
<p>The context mapper is the same as above, it's still the distinguished names of the objects that carry the attribute <em>uniqueMember</em> we're interested in. The search is also the same as above. But as <em>uniqueMember</em> is a list we need to iterate all the members in the list and replace the old value with the new:</p>
<pre>
for (Name someObjectDn: hits) {
    DirContextOperations context = ldapTemplate.lookupContext(someObjectDn);
    String[] members = context.getStringAttributes("uniqueMember");

     for (int i = 0; i < members.length; i++) {
            if (members[i].equals("uid=old.uid, dc=jayway, dc=com")) {
                members[i] = "uid=new.uid, dc=jayway, dc=com";

                break;
            }
    }

    context.setAttributeValues("uniqueMember", members);

    ldapTemplate.modifyAttributes(context);
}
</pre>
<h3>Conclusion</h3>
<p>It's easy to get the same functionality as the <em>Referential Integrity</em> using only Spring LDAP with very little custom code. You can introduce relationship attributes in new object classes and one method call will handle them all. An upside is that the filters use string values, so your relations attributes are not forced to contain distinguished names, but might be other values like uid or guid. However, using distinguished name is recommended.</p>
<p>As the searches all start from base, the searches might be less efficient as it scans the whole directory structure for the attribute. So this isn't recommended on non-indexed attributes when having large data volumes. The same applies to using the Referential Integrity within the directory server.</p>
<p>Thanks to Ulrik Sandberg and Andreas Andersson for their inputs on this blog.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jayway.com/2009/12/07/referential-integrity-using-spring-ldap/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
