directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Directory Server v1.5 > 6.1 How to write a simple custom partition for ApacheDS
Date Mon, 23 Nov 2009 15:44:00 GMT
<html>
<head>
    <base href="http://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1519/1/1/_/styles/combined.css?spaceKey=DIRxSRVx11&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background-color: white" bgcolor="white">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
     <h2><a href="http://cwiki.apache.org/confluence/display/DIRxSRVx11/6.1+How+to+write+a+simple+custom+partition+for+ApacheDS">6.1
How to write a simple custom partition for ApacheDS</a></h2>
     <h4>Page <b>edited</b> by             <a href="http://cwiki.apache.org/confluence/display/~szoerner">Stefan
Zoerner</a>
    </h4>
     
          <br/>
     <div class="notificationGreySide">
         <style type='text/css'>/*<![CDATA[*/
table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color:
#f0f0f0}
table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}

/*]]>*/</style><div class="Scrollbar"><table class='ScrollbarTable'><tr><td
width='33%' class='ScrollbarPrevName'>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/DIRxSRVx11/6.+Extending+the+server"><img border='0' align='middle'
src='/confluence/images/icons/up_16.gif' width='8' height='8'></a></sup><a
href="/confluence/display/DIRxSRVx11/6.+Extending+the+server">6. Extending the server</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;<a href="/confluence/display/DIRxSRVx11/6.2.+Implementing+an+Interceptor">6.2.
Implementing an Interceptor</a></td><td class='ScrollbarNextIcon'><a
href="/confluence/display/DIRxSRVx11/6.2.+Implementing+an+Interceptor"><img border='0'
align='middle' src='/confluence/images/icons/forwd_16.gif' width='16' height='16'></a></td></tr></table></div>
<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/warning.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td><b>Be Careful</b><br
/><p>Work in progress. Any feedback highly appreciated!</p></td></tr></table></div>

<h1><a name="6.1HowtowriteasimplecustompartitionforApacheDS-WritingasimplecustompartitionforApacheDS"></a>Writing
a simple custom partition for ApacheDS</h1>

<div class='panelMacro'><table class='tipMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/check.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td><b>ApacheDS 1.5.5</b><br
/>This site was updated for ApacheDS 1.5.5.</td></tr></table></div>

<p>On the mailing list, people ask regularly on how to write a custom partition. If
you simply plan to add another suffix to ApacheDS (besides dc=example,dc=com, for instance)
in order to store data, it is not necessary to write any code. You can simply add some lines
to the configuration. The following is for developers who plan to implement another storage
mechanism than the provided default.</p>

<div>
<ul>
    <li><a href='#6.1HowtowriteasimplecustompartitionforApacheDS-Whatexactlyisapartition%3F'>What
exactly is a partition?</a></li>
    <li><a href='#6.1HowtowriteasimplecustompartitionforApacheDS-Helloworld.Aminimalpartition'>Hello
world. A minimal partition</a></li>
<ul>
    <li><a href='#6.1HowtowriteasimplecustompartitionforApacheDS-Thesources'>The
sources</a></li>
    <li><a href='#6.1HowtowriteasimplecustompartitionforApacheDS-ImplementingtheclassHelloWorldPartition'>Implementing
the class HelloWorldPartition</a></li>
    <li><a href='#6.1HowtowriteasimplecustompartitionforApacheDS-Usingthepartition'>Using
the partition</a></li>
    <li><a href='#6.1HowtowriteasimplecustompartitionforApacheDS-Verification'>Verification</a></li>
</ul>
    <li><a href='#6.1HowtowriteasimplecustompartitionforApacheDS-Tobecontinued'>To
be continued</a></li>
</ul></div>

<h2><a name="6.1HowtowriteasimplecustompartitionforApacheDS-Whatexactlyisapartition%3F"></a>What
exactly is a partition?</h2>

<p>Within ApacheDS, a partition is a physically distinct store for a subset of the entries
contained within the server. A partition can be implemented using any storage mechanism or
can even be backed in memory. The default storage mechanism for a partition is <a href="http://jdbm.sourceforge.net"
rel="nofollow">JDBM</a>.</p>

<p>Implementing your own partition is basically implementing the <em>Partition</em>
interface from the <em>org.apache.directory.server.core.partition</em> package.
 Please note that this is not an easy task. Nevertheless I try to give you a starting point
with some simple examples.</p>

<h2><a name="6.1HowtowriteasimplecustompartitionforApacheDS-Helloworld.Aminimalpartition"></a>Hello
world. A minimal partition</h2>

<p>Let's start with a minimal partition, the <a href="http://en.wikipedia.org/wiki/Hello_world_program"
rel="nofollow">hello world</a>. Minimal means here, that it is possible to add it
to ApacheDS and see it with an LDAP browser. The partition ...</p>

<ul>
	<li>correctly implements the <em>Partition</em> interface</li>
	<li>is pluggable in the server (embedded and declarative in the configuration)</li>
	<li>is visible for clients like <em>ldapsearch</em> or Apache Directory
Studio</li>
	<li>contains one entry, which contains the famous "hello, world" message in an attribute
value</li>
	<li>does not support any modification operations like delete, add etc.</li>
	<li>does not take account of filters in search requests, ...</li>
</ul>


<h3><a name="6.1HowtowriteasimplecustompartitionforApacheDS-Thesources"></a>The
sources</h3>

<p>Currently, the sources are checked in here</p>
<ul>
	<li><a href="http://svn.apache.org/repos/asf/directory/sandbox/szoerner/helloWorldPartition"
rel="nofollow">http://svn.apache.org/repos/asf/directory/sandbox/szoerner/helloWorldPartition</a></li>
</ul>


<p>In order to build it, simply check it out and type "mvn install". </p>

<h3><a name="6.1HowtowriteasimplecustompartitionforApacheDS-ImplementingtheclassHelloWorldPartition"></a>Implementing
the class HelloWorldPartition </h3>

<p>The following UML class diagram depicts the structure of the little example.</p>

<p><img src="/confluence/download/attachments/103569/helloWorld_UML.png" align="absmiddle"
border="0" /></p>

<p>In order to be a partition, class <em>HelloWorldPartition</em> implements
the corresponding interface from <em>org.apache.directory.server.core.partition</em>.
It has an association to it's only entry (which will hold the "hello, world" method). This
entry is created in the <em>init</em> life cycle method of the partition, which
looks like this:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
...
<span class="code-keyword">public</span> void init(DirectoryService core) <span
class="code-keyword">throws</span> Exception {
                        
  <span class="code-comment">// Create LDAP DN
</span>  suffixDn = <span class="code-keyword">new</span> LdapDN(suffix);
  suffixDn.normalize(core.getRegistries().getAttributeTypeRegistry().getNormalizerMapping());
  Rdn rdn = suffixDn.getRdn();
        
  <span class="code-comment">// Create the only entry in <span class="code-keyword">this</span>
partition
</span>  ServerEntry entry = <span class="code-keyword">new</span> DefaultServerEntry(core
          .getRegistries(), <span class="code-keyword">this</span>.suffixDn);
  entry.put(SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
                SchemaConstants.ORGANIZATIONAL_UNIT_OC);        
  entry.put(SchemaConstants.OU_AT, rdn.getUpValue().toString());
  entry.put(<span class="code-quote">"description"</span>, <span class="code-quote">"hello,
world"</span>, <span class="code-quote">"a minimal partition"</span>);
        
  <span class="code-keyword">this</span>.helloEntry = entry;
}
...
</pre>
</div></div>

<p>We assume that the suffix starts with "ou=" in order to create an entry of object
class organizational unit. If someone tries to set a suffix which starts with another attribute
for the RDN, the <em>setSuffix</em> will throw an exception.</p>

<p>The <em>Partition</em> interface requires to implement many methods for
all the operations a partition should support (adding, deleting, modifying entries ...). Due
to the fact, that this is a read only partition, the implementation in our case is minimalistic.
Here is the <em>delete</em> method as an example.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
...
<span class="code-keyword">public</span> void delete(DeleteOperationContext opContext)
        <span class="code-keyword">throws</span> LdapOperationNotSupportedException
{
    <span class="code-keyword">throw</span> <span class="code-keyword">new</span>
LdapOperationNotSupportedException(
            MODIFICATION_NOT_ALLOWED_MSG, ResultCodeEnum.UNWILLING_TO_PERFORM);
}
...
</pre>
</div></div>

<p>Although this example should be minimal, some methods need more attention. At least
if we want to see the partitiion in an LDAP and not only in the error logs ...</p>

<p>The important methods are <em>hasEntry</em>, <em>lookup</em>
and <em>search</em>. The following code is the search method. Please note that
it ignores search scopes other than <em>BASE</em> and search filters completely
in order to have simple code.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> EntryFilteringCursor search(SearchOperationContext
ctx)
        <span class="code-keyword">throws</span> Exception {

    <span class="code-keyword">if</span> (ctx.getDn().equals(<span class="code-keyword">this</span>.suffixDn))
{
        <span class="code-keyword">switch</span> (ctx.getScope()) {
        <span class="code-keyword">case</span> OBJECT:
            <span class="code-comment">// <span class="code-keyword">return</span>
a result with the only entry we have
</span>            <span class="code-keyword">return</span> <span class="code-keyword">new</span>
BaseEntryFilteringCursor(
                    <span class="code-keyword">new</span> SingletonCursor&lt;ServerEntry&gt;(<span
class="code-keyword">this</span>.helloEntry), ctx);
        }
    }

    <span class="code-comment">// <span class="code-keyword">return</span>
an empty result
</span>    <span class="code-keyword">return</span> <span class="code-keyword">new</span>
BaseEntryFilteringCursor(<span class="code-keyword">new</span> EmptyCursor&lt;ServerEntry&gt;(),
ctx);
}
</pre>
</div></div>

<p>For the other methods, take a look in the <a href="http://svn.apache.org/repos/asf/directory/sandbox/szoerner/helloWorldPartition/src/main/java/org/apache/directory/samples/partition/hello/HelloWorldPartition.java"
title="svn.apache.org" rel="nofollow">source code</a>. </p>

<h3><a name="6.1HowtowriteasimplecustompartitionforApacheDS-Usingthepartition"></a>Using
the partition</h3>

<h4><a name="6.1HowtowriteasimplecustompartitionforApacheDS-Embeddedmode"></a>Embedded
mode</h4>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">package</span> org.apache.directory.samples.partition.hello;

<span class="code-keyword">import</span> org.apache.directory.server.core.DefaultDirectoryService;
<span class="code-keyword">import</span> org.apache.directory.server.core.DirectoryService;
<span class="code-keyword">import</span> org.apache.directory.server.ldap.LdapServer;
<span class="code-keyword">import</span> org.apache.directory.server.protocol.shared.transport.TcpTransport;

/**
 * Starts the server with the HelloWorld partition.
 */
<span class="code-keyword">public</span> class Main {

    <span class="code-keyword">public</span> <span class="code-keyword">static</span>
void main(<span class="code-object">String</span>[] args) <span class="code-keyword">throws</span>
Exception {

        DirectoryService directoryService = <span class="code-keyword">new</span>
DefaultDirectoryService();
        directoryService.setShutdownHookEnabled(<span class="code-keyword">true</span>);

        LdapServer ldapServer = <span class="code-keyword">new</span> LdapServer();
        ldapServer.setDirectoryService(directoryService);
        ldapServer.setAllowAnonymousAccess(<span class="code-keyword">true</span>);

        TcpTransport ldapTransport = <span class="code-keyword">new</span> TcpTransport(10389);
        ldapServer.setTransports(ldapTransport);

        HelloWorldPartition helloPartition = <span class="code-keyword">new</span>
HelloWorldPartition();
        helloPartition.setSuffix(<span class="code-quote">"ou=helloWorld"</span>);
        helloPartition.init(directoryService);

        directoryService.addPartition(helloPartition);

        directoryService.startup();
        ldapServer.start();
    }
}
</pre>
</div></div>

<h4><a name="6.1HowtowriteasimplecustompartitionforApacheDS-Addingittoaserver.xmlfile"></a>Adding
it to a server.xml file</h4>

<p>In order to use the partition in a standard installation of ApacheDS, simply add
it to the <em>server.xml</em> configuration. Provide a "native" Spring bean like
this. </p>

<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>server.xml</b></div><div class="codeContent
panelContent">
<pre class="code-xml">
&lt;spring:beans <span class="code-keyword">xmlns:spring</span>=<span class="code-quote">"http://xbean.apache.org/schemas/spring/1.0"</span>

			  <span class="code-keyword">xmlns:s</span>=<span class="code-quote">"http://www.springframework.org/schema/beans"</span>
			  xmlns=<span class="code-quote">"http://apacheds.org/config/1.0"</span>&gt;

  ...
   <span class="code-tag">&lt;defaultDirectoryService ...&gt;</span>
     ...
     <span class="code-tag">&lt;partitions&gt;</span>
     ...
      &lt;s:bean 
          id=<span class="code-quote">"helloPartition"</span> 
          class=<span class="code-quote">"org.apache.directory.samples.partition.hello.HelloWorldPartition"</span>&gt;
        <span class="code-tag">&lt;s:property name=<span class="code-quote">"suffix"</span>
value=<span class="code-quote">"ou=helloWorld"</span> /&gt;</span>
      <span class="code-tag">&lt;/s:bean&gt;</span>
    <span class="code-tag">&lt;/partitions&gt;</span>
   ...
  <span class="code-tag">&lt;/defaultDirectoryService&gt;</span>
...
</pre>
</div></div>

<p>Note that the class <em>HelloWorldPartition</em> has to be in the class
path of the server. Without, starting the server leads to a <em>ClassNotFoundException</em>.
You can copy the jar file which results from the build to the lib/ext directory. </p>

<h3><a name="6.1HowtowriteasimplecustompartitionforApacheDS-Verification"></a>Verification</h3>

<p>After adding the HelloWorldPartition to the directory service like above (embedded
or via configuration in <em>server.xml</em>), you can browse it with an LDAP browser
like the one from Apache Directory Studio. Here are some screen shots.</p>

<p><img src="/confluence/download/attachments/103569/helloWorldLDAPBrowser.png" align="absmiddle"
border="0" /></p>

<p><img src="/confluence/download/attachments/103569/helloWorldEntryEditor.png" align="absmiddle"
border="0" /></p>

<p>Of course using a command line tool works as well ...</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-none">
$ ldapsearch -h localhost -p 10389 -D "uid=admin,ou=system" -w secret \\
    -b "" -s base "(objectclass=*)" namingContexts
version: 1
dn:
namingContexts: ou=system
namingContexts: ou=helloWorld
namingContexts: ou=schema
$
$ ldapsearch -h localhost -p 10389 -D "uid=admin,ou=system" -w secret \\
    -b "ou=helloWorld" -s base "(objectclass=*)"

version: 1
dn: ou=helloWorld
objectClass: organizationalUnit
objectClass: top
description: hello, world
description: a minimal partition
ou: helloWorld
$
</pre>
</div></div>

<h2><a name="6.1HowtowriteasimplecustompartitionforApacheDS-Tobecontinued"></a>To
be continued</h2>

<p>We plan to add more sophistic examples on this topic in the near feature. Stay tuned
on the mailing lists.</p>

<p>Here is an older example on the topic:<br/>
<a href="http://svn.apache.org/viewvc/directory/sandbox/akarasulu/custom-partition" rel="nofollow">http://svn.apache.org/viewvc/directory/sandbox/akarasulu/custom-partition</a></p>

<p>It is outdated, but may still inspire you.</p>


     </div>
     <div id="commentsSection" class="wiki-content pageSection">
       <div style="float: right;">
            <a href="http://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
       </div>

       <a href="http://cwiki.apache.org/confluence/display/DIRxSRVx11/6.1+How+to+write+a+simple+custom+partition+for+ApacheDS">View
Online</a>
       |
       <a href="http://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=103569&revisedVersion=8&originalVersion=7">View
Change</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message