directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject svn commit: r982272 [1/2] - in /directory: apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/ apacheds/trunk/core/src/main/java/org/apache/direc...
Date Wed, 04 Aug 2010 14:53:23 GMT
Author: elecharny
Date: Wed Aug  4 14:53:22 2010
New Revision: 982272

URL: http://svn.apache.org/viewvc?rev=982272&view=rev
Log:
o Refactored the DnNode code : there is now only one class instead of three plus an interface
o Modified the DnNode class to allow branches to store an element (we need this for overlapping partitions and APs)
o Changed the api to be more consistent and more explicit
o Added extensive tests for the api
o Removed a test in the PartitionTreeTest class, as overlapping partition will be accepted in the partition tree
o Added code in the AdministrativePointInterceptor to create the list of APs for an entry

Removed:
    directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/tree/DnBranchNode.java
    directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/tree/DnLeafNode.java
Modified:
    directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ReferralManager.java
    directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AbstractAdministrativePoint.java
    directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AdministrativePoint.java
    directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AutonomousAdministrativePoint.java
    directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/InnerAdministrativePoint.java
    directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/SpecificAdministrativePoint.java
    directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
    directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManagerImpl.java
    directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java
    directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java
    directory/apacheds/trunk/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/tree/PartitionTreeTest.java
    directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/subtree/AdministrativeRole.java
    directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/tree/DnNode.java
    directory/shared/trunk/ldap/src/test/java/org/apache/directory/shared/ldap/name/DNTest.java
    directory/shared/trunk/ldap/src/test/java/org/apache/directory/shared/ldap/util/tree/TestDnNode.java

Modified: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ReferralManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ReferralManager.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ReferralManager.java (original)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/ReferralManager.java Wed Aug  4 14:53:22 2010
@@ -6,20 +6,21 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.server.core;
 
 import org.apache.directory.shared.ldap.entry.Entry;
+import org.apache.directory.shared.ldap.exception.LdapException;
 import org.apache.directory.shared.ldap.name.DN;
 
 /**
@@ -30,40 +31,40 @@ import org.apache.directory.shared.ldap.
 public interface ReferralManager
 {
     /**
-     * Get a read-lock on the referralManager. 
+     * Get a read-lock on the referralManager.
      * No read operation can be done on the referralManager if this
      * method is not called before.
      */
     void lockRead();
-    
-    
+
+
     /**
-     * Get a write-lock on the referralManager. 
+     * Get a write-lock on the referralManager.
      * No write operation can be done on the referralManager if this
      * method is not called before.
      */
     void lockWrite();
-    
-    
+
+
     /**
-     * Release the read-write lock on the referralManager. 
+     * Release the read-write lock on the referralManager.
      * This method must be called after having read or modified the
      * ReferralManager
      */
     void unlock();
-    
-    
+
+
     /**
      * Tells if a DN is a referral (its associated entry contains the Referral ObjectClass).
-     * 
+     *
      * It does not check that the associated entry inherits from a referral.
      *
      * @param dn The entry's DN we want to check
      * @return <code>true</code> if the DN is associated with a referral
      */
     boolean isReferral( DN dn );
-    
-    
+
+
     /**
      * Tells if this DN has a parent which is a referral.
      * <br>
@@ -74,8 +75,8 @@ public interface ReferralManager
      * @return <code>true</code> if there is a parent referral
      */
     boolean hasParentReferral( DN dn );
-    
-    
+
+
     /**
      * Get the DN of the parent referral for a specific DN
      *
@@ -83,24 +84,24 @@ public interface ReferralManager
      * @return The parent referral of null if none is found
      */
     Entry getParentReferral( DN dn );
-    
-    
+
+
     /**
      * Add a referral to the manager.
      *
      * @param dn The referral to add
      */
     void addReferral( Entry entry );
-    
-    
+
+
     /**
      * Remove a referral from the manager.
-     * 
+     *
      * @param dn The referral to remove
      */
-    void removeReferral( Entry entry );
-    
-    
+    void removeReferral( Entry entry ) throws LdapException;
+
+
     /**
      * Initialize the manager, reading all the referrals from the base.
      * The manager will search for every entries having a Referral ObjectClass.
@@ -111,7 +112,7 @@ public interface ReferralManager
      */
     void init( DirectoryService directoryService, String... suffixes ) throws Exception;
 
-    
+
     /**
      * Remove a partition from the manager, reading all the referrals from the base.
      * The manager will search for every entries having a Referral ObjectClass, and

Modified: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AbstractAdministrativePoint.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AbstractAdministrativePoint.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AbstractAdministrativePoint.java (original)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AbstractAdministrativePoint.java Wed Aug  4 14:53:22 2010
@@ -55,9 +55,12 @@ public abstract class AbstractAdministra
     }
 
     /**
-     * @return The administrativeRole
+     * {@inheritDoc}
      */
-    public abstract AdministrativeRole getRole();
+    public AdministrativeRole getRole()
+    {
+        return role;
+    }
 
 
     /**

Modified: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AdministrativePoint.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AdministrativePoint.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AdministrativePoint.java (original)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AdministrativePoint.java Wed Aug  4 14:53:22 2010
@@ -22,6 +22,7 @@ package org.apache.directory.server.core
 import java.util.Map;
 
 import org.apache.directory.shared.ldap.name.DN;
+import org.apache.directory.shared.ldap.subtree.AdministrativeRole;
 
 /**
  *
@@ -93,4 +94,10 @@ public interface AdministrativePoint
      * @param children the AdministrativePoint children
      */
     void setChildren( Map<String, AdministrativePoint> children );
+
+
+    /**
+     * @return The administrativeRole
+     */
+    AdministrativeRole getRole();
 }

Modified: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AutonomousAdministrativePoint.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AutonomousAdministrativePoint.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AutonomousAdministrativePoint.java (original)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/AutonomousAdministrativePoint.java Wed Aug  4 14:53:22 2010
@@ -34,7 +34,7 @@ public class AutonomousAdministrativePoi
      * @param dn The AdministrativePoint DN
      * @param uuid The AdministrativePoint UUID
      */
-    protected AutonomousAdministrativePoint( DN dn, String uuid )
+    public AutonomousAdministrativePoint( DN dn, String uuid )
     {
         super( dn, uuid, AdministrativeRole.AutonomousArea );
     }
@@ -47,13 +47,4 @@ public class AutonomousAdministrativePoi
     {
         return true;
     }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public AdministrativeRole getRole()
-    {
-        return AdministrativeRole.AutonomousArea;
-    }
 }

Modified: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/InnerAdministrativePoint.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/InnerAdministrativePoint.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/InnerAdministrativePoint.java (original)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/InnerAdministrativePoint.java Wed Aug  4 14:53:22 2010
@@ -35,7 +35,7 @@ public class InnerAdministrativePoint ex
      * @param uuid The AdministrativePoint UUID
      * @param role The AdministrativePoint role
      */
-    protected InnerAdministrativePoint( DN dn, String uuid, AdministrativeRole role )
+    public InnerAdministrativePoint( DN dn, String uuid, AdministrativeRole role )
     {
         super( dn, uuid, role );
     }
@@ -53,15 +53,6 @@ public class InnerAdministrativePoint ex
     /**
      * {@inheritDoc}
      */
-    public AdministrativeRole getRole()
-    {
-        return role;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
     public AdministrativePoint getParent()
     {
         return parent;

Modified: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/SpecificAdministrativePoint.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/SpecificAdministrativePoint.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/SpecificAdministrativePoint.java (original)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/administrative/SpecificAdministrativePoint.java Wed Aug  4 14:53:22 2010
@@ -35,7 +35,7 @@ public class SpecificAdministrativePoint
      * @param uuid The AdministrativePoint UUID
      * @param role The AdministrativePoint role
      */
-    protected SpecificAdministrativePoint( DN dn, String uuid, AdministrativeRole role )
+    public SpecificAdministrativePoint( DN dn, String uuid, AdministrativeRole role )
     {
         super( dn, uuid, role );
     }
@@ -53,15 +53,6 @@ public class SpecificAdministrativePoint
     /**
      * {@inheritDoc}
      */
-    public AdministrativeRole getRole()
-    {
-        return role;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
     public AdministrativePoint getParent()
     {
         return parent;

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java Wed Aug  4 14:53:22 2010
@@ -100,18 +100,18 @@ public class DefaultOperationManager imp
             {
                 // we have to replace the parent by the referral
                 LdapURL ldapUrl = new LdapURL( url.getString() );
-    
+
                 // We have a problem with the DN : we can't use the UpName,
                 // as we may have some spaces around the ',' and '+'.
-                // So we have to take the RDN one by one, and create a 
+                // So we have to take the RDN one by one, and create a
                 // new DN with the type and value UP form
-    
+
                 DN urlDn = ldapUrl.getDn().addAll( childDn );
-    
+
                 ldapUrl.setDn( urlDn );
                 urls.add( ldapUrl.toString() );
             }
-        } 
+        }
         catch ( LdapInvalidDnException lide )
         {
             throw new LdapOperationErrorException( lide.getMessage() );
@@ -157,7 +157,7 @@ public class DefaultOperationManager imp
                 {
                     // We have a problem with the DN : we can't use the UpName,
                     // as we may have some spaces around the ',' and '+'.
-                    // So we have to take the RDN one by one, and create a 
+                    // So we have to take the RDN one by one, and create a
                     // new DN with the type and value UP form
 
                     DN urlDn = ldapUrl.getDn().addAll( childDn );
@@ -235,7 +235,7 @@ public class DefaultOperationManager imp
             if ( directoryService.getReferralManager().hasParentReferral( dn ) )
             {
                 Entry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
-                DN childDn = ( DN ) dn.getSuffix( parentEntry.getDn().size() );
+                DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                 // Depending on the Context.REFERRAL property value, we will throw
                 // a different exception.
@@ -322,7 +322,7 @@ public class DefaultOperationManager imp
 
             if ( parentEntry != null )
             {
-                // We have found a parent referral for the current DN 
+                // We have found a parent referral for the current DN
                 DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                 if ( directoryService.getReferralManager().isReferral( dn ) )
@@ -401,7 +401,7 @@ public class DefaultOperationManager imp
 
             if ( parentEntry != null )
             {
-                // We have found a parent referral for the current DN 
+                // We have found a parent referral for the current DN
                 DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                 if ( directoryService.getReferralManager().isReferral( dn ) )
@@ -590,7 +590,7 @@ public class DefaultOperationManager imp
                         // Unlock the referral manager
                         referralManager.unlock();
 
-                        // We have found a parent referral for the current DN 
+                        // We have found a parent referral for the current DN
                         DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                         LdapReferralException exception = buildReferralException( parentEntry, childDn );
@@ -607,7 +607,7 @@ public class DefaultOperationManager imp
                     {
                         referralManager.unlock();
 
-                        // We have found a parent referral for the current DN 
+                        // We have found a parent referral for the current DN
                         DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                         LdapPartialResultException exception = buildLdapPartialResultException( childDn );
@@ -618,7 +618,7 @@ public class DefaultOperationManager imp
                         // Unlock the referral manager
                         referralManager.unlock();
 
-                        // We have found a parent referral for the current DN 
+                        // We have found a parent referral for the current DN
                         DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                         LdapReferralException exception = buildReferralException( parentEntry, childDn );
@@ -673,8 +673,8 @@ public class DefaultOperationManager imp
 
             if ( parentEntry != null )
             {
-                // We have found a parent referral for the current DN 
-                DN childDn = ( DN ) dn.getSuffix( parentEntry.getDn().size() );
+                // We have found a parent referral for the current DN
+                DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                 if ( directoryService.getReferralManager().isReferral( dn ) )
                 {
@@ -771,8 +771,8 @@ public class DefaultOperationManager imp
 
             if ( parentEntry != null )
             {
-                // We have found a parent referral for the current DN 
-                DN childDn = ( DN ) dn.getSuffix( parentEntry.getDn().size() );
+                // We have found a parent referral for the current DN
+                DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                 if ( directoryService.getReferralManager().isReferral( dn ) )
                 {
@@ -851,7 +851,7 @@ public class DefaultOperationManager imp
 
 
     /**
-     * {@inheritDoc} 
+     * {@inheritDoc}
      */
     public void rename( RenameOperationContext renameContext ) throws LdapException
     {
@@ -885,8 +885,8 @@ public class DefaultOperationManager imp
 
             if ( parentEntry != null )
             {
-                // We have found a parent referral for the current DN 
-                DN childDn = ( DN ) dn.getSuffix( parentEntry.getDn().size() );
+                // We have found a parent referral for the current DN
+                DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                 if ( directoryService.getReferralManager().isReferral( dn ) )
                 {
@@ -967,8 +967,8 @@ public class DefaultOperationManager imp
 
             if ( parentEntry != null )
             {
-                // We have found a parent referral for the current DN 
-                DN childDn = ( DN ) dn.getSuffix( parentEntry.getDn().size() );
+                // We have found a parent referral for the current DN
+                DN childDn = dn.getSuffix( parentEntry.getDn().size() );
 
                 if ( directoryService.getReferralManager().isReferral( dn ) )
                 {

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManagerImpl.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManagerImpl.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManagerImpl.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManagerImpl.java Wed Aug  4 14:53:22 2010
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.server.core;
 
@@ -38,13 +38,13 @@ import org.apache.directory.shared.ldap.
 import org.apache.directory.shared.ldap.message.AliasDerefMode;
 import org.apache.directory.shared.ldap.name.DN;
 import org.apache.directory.shared.ldap.schema.AttributeType;
-import org.apache.directory.shared.ldap.util.tree.DnBranchNode;
+import org.apache.directory.shared.ldap.util.tree.DnNode;
 
 
 /**
  * Implement a referral Manager, handling the requests from the LDAP protocol.
  * <br>
- * Referrals are stored in a tree, where leaves are the referrals. We are using 
+ * Referrals are stored in a tree, where leaves are the referrals. We are using
  * the very same structure than for the partition manager.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
@@ -52,7 +52,7 @@ import org.apache.directory.shared.ldap.
 public class ReferralManagerImpl implements ReferralManager
 {
     /** The referrals tree */
-    private DnBranchNode<Entry> referrals;
+    private DnNode<Entry> referrals;
 
     /** A lock to guarantee the manager consistency */
     private ReentrantReadWriteLock mutex = new ReentrantReadWriteLock();
@@ -60,9 +60,9 @@ public class ReferralManagerImpl impleme
     /** A storage for the ObjectClass attributeType */
     private AttributeType OBJECT_CLASS_AT;
 
-    
+
     /**
-     * 
+     *
      * Creates a new instance of ReferralManagerImpl.
      *
      * @param directoryService The directory service
@@ -71,8 +71,8 @@ public class ReferralManagerImpl impleme
     public ReferralManagerImpl( DirectoryService directoryService ) throws LdapException
     {
         lockWrite();
-        
-        referrals = new DnBranchNode<Entry>();
+
+        referrals = new DnNode<Entry>();
         PartitionNexus nexus = directoryService.getPartitionNexus();
 
         Set<String> suffixes = nexus.listSuffixes();
@@ -82,10 +82,10 @@ public class ReferralManagerImpl impleme
 
         unlock();
     }
-    
-    
+
+
     /**
-     * Get a read-lock on the referralManager. 
+     * Get a read-lock on the referralManager.
      * No read operation can be done on the referralManager if this
      * method is not called before.
      */
@@ -93,10 +93,10 @@ public class ReferralManagerImpl impleme
     {
         mutex.readLock().lock();
     }
-    
-    
+
+
     /**
-     * Get a write-lock on the referralManager. 
+     * Get a write-lock on the referralManager.
      * No write operation can be done on the referralManager if this
      * method is not called before.
      */
@@ -105,9 +105,9 @@ public class ReferralManagerImpl impleme
         mutex.writeLock().lock();
     }
 
-    
+
     /**
-     * Release the read-write lock on the referralManager. 
+     * Release the read-write lock on the referralManager.
      * This method must be called after having read or modified the
      * ReferralManager
      */
@@ -122,8 +122,8 @@ public class ReferralManagerImpl impleme
             mutex.readLock().unlock();
         }
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
@@ -133,7 +133,7 @@ public class ReferralManagerImpl impleme
     {
         try
         {
-            ((DnBranchNode<Entry>)referrals).add( entry.getDn(), entry );
+            referrals.add( entry.getDn(), entry );
         }
         catch ( LdapException ne )
         {
@@ -147,14 +147,14 @@ public class ReferralManagerImpl impleme
      */
     public void init( DirectoryService directoryService, String... suffixes ) throws LdapException
     {
-        ExprNode referralFilter = new EqualityNode<String>( OBJECT_CLASS_AT, 
+        ExprNode referralFilter = new EqualityNode<String>( OBJECT_CLASS_AT,
             new StringValue( SchemaConstants.REFERRAL_OC ) );
 
         // Lookup for each entry with the ObjectClass = Referral value
         SearchControls searchControl = new SearchControls();
         searchControl.setReturningObjFlag( false );
         searchControl.setSearchScope( SearchControls.SUBTREE_SCOPE );
-        
+
         CoreSession adminSession = directoryService.getAdminSession();
         PartitionNexus nexus = directoryService.getPartitionNexus();
 
@@ -162,30 +162,30 @@ public class ReferralManagerImpl impleme
         {
             // We will store each entry's DN into the Referral tree
             DN suffixDn = DNFactory.create( suffix, directoryService.getSchemaManager() );
-            
+
             SearchOperationContext searchOperationContext = new SearchOperationContext( adminSession, suffixDn, referralFilter, searchControl );
             searchOperationContext.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );
             EntryFilteringCursor cursor = nexus.search( searchOperationContext );
-            
+
             try
             {
                 // Move to the first entry in the cursor
                 cursor.beforeFirst();
-                
-                while ( cursor.next() ) 
+
+                while ( cursor.next() )
                 {
                     Entry entry = cursor.get();
-    
+
                     // Lock the referralManager
                     lockWrite();
-                    
+
                     // Add it at the right place
                     addReferral( entry );
-                    
+
                     // Unlock the referralManager
                     unlock();
                 }
-                
+
                 cursor.close();
             }
             catch ( Exception e )
@@ -194,21 +194,21 @@ public class ReferralManagerImpl impleme
             }
         }
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
     public void remove( DirectoryService directoryService, DN suffix ) throws Exception
     {
-        ExprNode referralFilter = new EqualityNode<String>( OBJECT_CLASS_AT, 
+        ExprNode referralFilter = new EqualityNode<String>( OBJECT_CLASS_AT,
             new StringValue( SchemaConstants.REFERRAL_OC ) );
 
         // Lookup for each entry with the ObjectClass = Referral value
         SearchControls searchControl = new SearchControls();
         searchControl.setReturningObjFlag( false );
         searchControl.setSearchScope( SearchControls.SUBTREE_SCOPE );
-        
+
         CoreSession adminSession = directoryService.getAdminSession();
         PartitionNexus nexus = directoryService.getPartitionNexus();
 
@@ -217,26 +217,28 @@ public class ReferralManagerImpl impleme
             referralFilter, searchControl );
         searchOperationContext.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS );
         EntryFilteringCursor cursor = nexus.search( searchOperationContext );
-        
+
         // Move to the first entry in the cursor
         cursor.beforeFirst();
-        
-        while ( cursor.next() ) 
+
+        while ( cursor.next() )
         {
             Entry entry = cursor.get();
-            
+
             // Add it at the right place
             removeReferral( entry );
         }
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
     public boolean hasParentReferral( DN dn )
     {
-        return referrals.hasParentElement( dn );
+        DnNode<Entry> referral = referrals.getNode( dn );
+
+        return ( referral != null ) && referral.isLeaf();
     }
 
 
@@ -249,18 +251,18 @@ public class ReferralManagerImpl impleme
         {
             return null;
         }
-        
-        return referrals.getParentElement( dn );
+
+        return referrals.getElement( dn );
     }
 
-    
+
     /**
      * {@inheritDoc}
      */
     public boolean isReferral( DN dn )
     {
-        Entry parent = referrals.getParentElement( dn );
-        
+        Entry parent = referrals.getElement( dn );
+
         if ( parent != null )
         {
             return dn.equals( parent.getDn() );
@@ -275,8 +277,8 @@ public class ReferralManagerImpl impleme
     /**
      * {@inheritDoc}
      */
-    public void removeReferral( Entry entry )
+    public void removeReferral( Entry entry ) throws LdapException
     {
-        referrals.remove( entry );
+        referrals.remove( entry.getDn() );
     }
 }

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/admin/AdministrativePointInterceptor.java Wed Aug  4 14:53:22 2010
@@ -31,6 +31,10 @@ import org.apache.directory.server.core.
 import org.apache.directory.server.core.DefaultCoreSession;
 import org.apache.directory.server.core.DirectoryService;
 import org.apache.directory.server.core.LdapPrincipal;
+import org.apache.directory.server.core.administrative.AdministrativePoint;
+import org.apache.directory.server.core.administrative.AutonomousAdministrativePoint;
+import org.apache.directory.server.core.administrative.InnerAdministrativePoint;
+import org.apache.directory.server.core.administrative.SpecificAdministrativePoint;
 import org.apache.directory.server.core.authn.Authenticator;
 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
 import org.apache.directory.server.core.interceptor.BaseInterceptor;
@@ -67,6 +71,7 @@ import org.apache.directory.shared.ldap.
 import org.apache.directory.shared.ldap.schema.SchemaManager;
 import org.apache.directory.shared.ldap.subtree.AdministrativeRole;
 import org.apache.directory.shared.ldap.util.StringTools;
+import org.apache.directory.shared.ldap.util.tree.DnNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -151,6 +156,8 @@ public class AdministrativePointIntercep
         SPECIFIC_AREA_ROLES.add( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID );
     }
 
+    private DnNode<List<AdministrativePoint>> adminPointCache;
+
 
     /**
      * Tells if the given role is a InnerArea role
@@ -202,6 +209,204 @@ public class AdministrativePointIntercep
         return false;
     }
 
+
+    /**
+     * Create the list of AP for a given entry
+     */
+    private List<AdministrativePoint> createAdministrativePoints( EntryAttribute adminPoint, DN dn, String uuid )
+    {
+        List<AdministrativePoint> adminPoints = new ArrayList<AdministrativePoint> ();
+
+        for ( Value<?> value : adminPoint )
+        {
+            String role = value.getString();
+
+            // Deal with Autonomous AP
+            if ( role.equalsIgnoreCase( SchemaConstants.AUTONOMOUS_AREA ) ||
+                 role.equalsIgnoreCase( SchemaConstants.AUTONOMOUS_AREA_OID ) )
+            {
+                AdministrativePoint aap = new AutonomousAdministrativePoint( dn, uuid );
+                adminPoints.add( aap );
+
+                // If it's an AAP, we can get out immediately
+                return adminPoints;
+            }
+
+            // Deal with AccessControl AP
+            if ( role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA ) ||
+                 role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_SPECIFIC_AREA_OID ) )
+            {
+                AdministrativePoint sap = new SpecificAdministrativePoint( dn, uuid, AdministrativeRole.AccessControlSpecificArea );
+                adminPoints.add( sap );
+
+                continue;
+            }
+
+            if ( role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_INNER_AREA ) ||
+                 role.equalsIgnoreCase( SchemaConstants.ACCESS_CONTROL_INNER_AREA_OID ) )
+            {
+                AdministrativePoint iap = new InnerAdministrativePoint( dn, uuid, AdministrativeRole.AccessControlInnerArea );
+                adminPoints.add( iap );
+
+                continue;
+            }
+
+            // Deal with CollectveAttribute AP
+            if ( role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA ) ||
+                 role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_SPECIFIC_AREA_OID ) )
+            {
+                AdministrativePoint sap = new SpecificAdministrativePoint( dn, uuid, AdministrativeRole.CollectiveAttributeSpecificArea );
+                adminPoints.add( sap );
+
+                continue;
+            }
+
+            if ( role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA ) ||
+                 role.equalsIgnoreCase( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA_OID ) )
+            {
+                AdministrativePoint iap = new InnerAdministrativePoint( dn, uuid, AdministrativeRole.CollectiveAttributeInnerArea );
+                adminPoints.add( iap );
+
+                continue;
+            }
+
+            // Deal with SubSchema AP
+            if ( role.equalsIgnoreCase( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA ) ||
+                 role.equalsIgnoreCase( SchemaConstants.SUB_SCHEMA_ADMIN_SPECIFIC_AREA_OID ) )
+            {
+                AdministrativePoint sap = new SpecificAdministrativePoint( dn, uuid, AdministrativeRole.SubSchemaSpecificArea );
+                adminPoints.add( sap );
+
+                continue;
+            }
+
+            // Deal with TriggerExecution AP
+            if ( role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA ) ||
+                 role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_SPECIFIC_AREA_OID ) )
+            {
+                AdministrativePoint sap = new SpecificAdministrativePoint( dn, uuid, AdministrativeRole.TriggerExecutionSpecificArea );
+                adminPoints.add( sap );
+
+                continue;
+            }
+
+            if ( role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA ) ||
+                 role.equalsIgnoreCase( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA_OID ) )
+            {
+                AdministrativePoint iap = new InnerAdministrativePoint( dn, uuid, AdministrativeRole.TriggerExecutionInnerArea );
+                adminPoints.add( iap );
+
+                continue;
+            }
+        }
+
+        return adminPoints;
+    }
+
+
+    private AdministrativePoint getParent( AdministrativePoint ap, List<AdministrativePoint> aps, AdministrativeRole role, DnNode<List<AdministrativePoint>> currentNode )
+    {
+        AdministrativePoint parent = null;
+
+        for ( AdministrativePoint adminPoint : aps )
+        {
+            if ( adminPoint.isAutonomous() || ( adminPoint.getRole() == ap.getRole() ) )
+            {
+                // Same role or AP : this is the parent
+                return adminPoint;
+            }
+            else if ( adminPoint.getRole() == role )
+            {
+                parent = adminPoint;
+            }
+        }
+
+        if ( parent != null )
+        {
+            return parent;
+        }
+
+        // We have to go down one level
+        if ( currentNode.hasParent() )
+        {
+            return findParent( ap, currentNode );
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+
+    private AdministrativePoint findParent( AdministrativePoint ap, DnNode<List<AdministrativePoint>> currentNode )
+    {
+        List<AdministrativePoint> aps = currentNode.getElement();
+
+        if ( aps != null )
+        {
+            // Check if the current element is a valid parent
+            switch ( ap.getRole() )
+            {
+                case AutonomousArea :
+                    AdministrativePoint currentAp = aps.get( 0 );
+
+                    if ( currentAp.isAutonomous() )
+                    {
+                        return currentAp;
+                    }
+                    else
+                    {
+                        // We have to go down one level, as an AAP
+                        // must have another AAP as a parent
+                        if ( currentNode.hasParent() )
+                        {
+                            return findParent( ap, currentNode );
+                        }
+                        else
+                        {
+                            return null;
+                        }
+                    }
+
+                case AccessControlInnerArea :
+                    return getParent( ap, aps, AdministrativeRole.AccessControlSpecificArea, currentNode );
+
+                case CollectiveAttributeInnerArea :
+                    return getParent( ap, aps, AdministrativeRole.CollectiveAttributeSpecificArea, currentNode );
+
+                case TriggerExecutionInnerArea :
+                    return getParent( ap, aps, AdministrativeRole.TriggerExecutionSpecificArea, currentNode );
+
+                case AccessControlSpecificArea :
+                    return getParent( ap, aps, AdministrativeRole.AccessControlSpecificArea, currentNode );
+
+                case CollectiveAttributeSpecificArea :
+                    return getParent( ap, aps, AdministrativeRole.CollectiveAttributeSpecificArea, currentNode );
+
+                case SubSchemaSpecificArea :
+                    return getParent( ap, aps, AdministrativeRole.SubSchemaSpecificArea, currentNode );
+
+                case TriggerExecutionSpecificArea :
+                    return getParent( ap, aps, AdministrativeRole.TriggerExecutionSpecificArea, currentNode );
+
+                default :
+                    return null;
+            }
+        }
+        else
+        {
+            if ( currentNode.hasParent() )
+            {
+                return findParent( ap, currentNode.getParent() );
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }
+
     /**
      * Creates an Administrative service interceptor.
      */
@@ -312,6 +517,9 @@ public class AdministrativePointIntercep
         List<Entry> accessControlIAPs = getAdministrativePoints( SchemaConstants.ACCESS_CONTROL_INNER_AREA );
         List<Entry> collectiveAttributeIAPs = getAdministrativePoints( SchemaConstants.COLLECTIVE_ATTRIBUTE_INNER_AREA );
         List<Entry> triggerExecutionIAPs = getAdministrativePoints( SchemaConstants.TRIGGER_EXECUTION_INNER_AREA );
+
+        // Create the root AdministrativePoint cache. The first DN
+        adminPointCache = new DnNode<List<AdministrativePoint>>();
     }
 
 
@@ -413,8 +621,29 @@ public class AdministrativePointIntercep
 
         // Now, update the cache
         String uuid = addContext.getEntry().get( ENTRY_UUID_AT ).getString();
-        AdministrativeRole adminRole = null;
 
+        // Construct the AdministrativePoint objects
+        List<AdministrativePoint> administrativePoints = createAdministrativePoints( adminPoint, addContext.getDn(), uuid );
+
+        for ( AdministrativePoint ap : administrativePoints )
+        {
+            if ( ap.isAutonomous() )
+            {
+                // Find the parent
+                AdministrativePoint parent = findParent( ap, adminPointCache );
+                ap.setParent( parent );
+
+                // We won't have any children as the entry has just been added
+            }
+            else
+            {
+                // Find the parent
+                AdministrativePoint parent = findParent( ap,  adminPointCache );
+                ap.setParent( parent );
+
+                // We won't have any children as the entry has just been added
+            }
+        }
 
         LOG.debug( "Added an Autonomous Administrative Point at {}", entry.getDn() );
 

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java Wed Aug  4 14:53:22 2010
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.server.core.partition;
 
@@ -100,7 +100,7 @@ import org.apache.directory.shared.ldap.
 import org.apache.directory.shared.ldap.schema.UsageEnum;
 import org.apache.directory.shared.ldap.util.DateUtils;
 import org.apache.directory.shared.ldap.util.NamespaceTools;
-import org.apache.directory.shared.ldap.util.tree.DnBranchNode;
+import org.apache.directory.shared.ldap.util.tree.DnNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -137,7 +137,7 @@ public class DefaultPartitionNexus exten
     private Map<String, Partition> partitions = new HashMap<String, Partition>();
 
     /** A structure to hold all the partitions */
-    private DnBranchNode<Partition> partitionLookupTree = new DnBranchNode<Partition>();
+    private DnNode<Partition> partitionLookupTree = new DnNode<Partition>();
 
     /** the system partition */
     private Partition system;
@@ -689,10 +689,10 @@ public class DefaultPartitionNexus exten
     {
         // Get the current partition
         Partition backend = getPartition( moveContext.getDn() );
-        
+
         // We also have to get the new partition as it can be different
         //Partition newBackend = getPartition( opContext.getNewDn() );
-        
+
         backend.move( moveContext );
     }
 
@@ -807,7 +807,7 @@ public class DefaultPartitionNexus exten
         ExprNode filter = searchContext.getFilter();
 
         // TODO since we're handling the *, and + in the EntryFilteringCursor
-        // we may not need this code: we need see if this is actually the 
+        // we may not need this code: we need see if this is actually the
         // case and remove this code.
         if ( base.size() == 0 )
         {
@@ -844,7 +844,7 @@ public class DefaultPartitionNexus exten
             else if ( isOnelevelScope )
             {
                 List<EntryFilteringCursor> cursors = new ArrayList<EntryFilteringCursor>();
-                
+
                 for ( Partition partition : partitions.values() )
                 {
                     searchContext.setDn( partition.getSuffix() );
@@ -857,12 +857,12 @@ public class DefaultPartitionNexus exten
             else if ( isSublevelScope )
             {
                 List<EntryFilteringCursor> cursors = new ArrayList<EntryFilteringCursor>();
-                
+
                 for ( Partition partition : partitions.values() )
                 {
                     ClonedServerEntry entry = partition.lookup( new LookupOperationContext( directoryService.getAdminSession(),
                         partition.getSuffix() ) );
-                    
+
                     if ( entry != null )
                     {
                         Partition backend = getPartition( entry.getDn() );
@@ -871,7 +871,7 @@ public class DefaultPartitionNexus exten
                     }
                 }
 
-                // don't feed the above Cursors' list to a BaseEntryFilteringCursor it is skipping the naming context entry of each partition 
+                // don't feed the above Cursors' list to a BaseEntryFilteringCursor it is skipping the naming context entry of each partition
                 return new CursorList( cursors, searchContext );
             }
 
@@ -885,7 +885,7 @@ public class DefaultPartitionNexus exten
         }
 
         Partition backend = getPartition( base );
-        
+
         return backend.search( searchContext );
     }
 
@@ -995,9 +995,9 @@ public class DefaultPartitionNexus exten
         }
 
         // Update the partition tree
-        partitionLookupTree.remove( partition );
+        partitionLookupTree.remove( partition.getSuffix() );
         partitions.remove( key );
-        
+
         try
         {
             partition.destroy();
@@ -1023,7 +1023,7 @@ public class DefaultPartitionNexus exten
      */
     public Partition getPartition( DN dn ) throws LdapException
     {
-        Partition parent = partitionLookupTree.getParentElement( dn );
+        Partition parent = partitionLookupTree.getElement( dn );
 
         if ( parent == null )
         {
@@ -1042,11 +1042,11 @@ public class DefaultPartitionNexus exten
     public DN findSuffix( DN dn ) throws LdapException
     {
         Partition backend = getPartition( dn );
-        
+
         return backend.getSuffix();
     }
-    
-    
+
+
     public DN getSuffix()
     {
         return null;

Modified: directory/apacheds/trunk/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/tree/PartitionTreeTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/tree/PartitionTreeTest.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/apacheds/trunk/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/tree/PartitionTreeTest.java (original)
+++ directory/apacheds/trunk/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/tree/PartitionTreeTest.java Wed Aug  4 14:53:22 2010
@@ -23,14 +23,12 @@ package org.apache.directory.server.core
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import org.apache.directory.server.core.partition.Partition;
 import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
 import org.apache.directory.shared.ldap.exception.LdapException;
 import org.apache.directory.shared.ldap.name.DN;
-import org.apache.directory.shared.ldap.util.tree.DnBranchNode;
-import org.apache.directory.shared.ldap.util.tree.DnLeafNode;
+import org.apache.directory.shared.ldap.name.RDN;
 import org.apache.directory.shared.ldap.util.tree.DnNode;
 import org.junit.Test;
 
@@ -48,24 +46,24 @@ public class PartitionTreeTest
     @Test public void testNewPartitionTree() throws LdapException
     {
         /** A structure to hold all the partitions */
-        DnBranchNode<Partition> partitionLookupTree = new DnBranchNode<Partition>();
-        
+        DnNode<Partition> partitionLookupTree = new DnNode<Partition>();
+
         DN suffix = new DN( "dc=example, dc=com" );
         Partition partition = new JdbmPartition();
         partition.setSuffix( suffix );
-        
+
         partitionLookupTree.add( suffix, partition );
-        
+
         assertNotNull( partitionLookupTree );
-        assertTrue( partitionLookupTree instanceof DnBranchNode );
-        assertTrue( ((DnBranchNode<Partition>)partitionLookupTree).contains( "dc=com" ) );
-        
-        DnNode<Partition> child = ((DnBranchNode<Partition>)partitionLookupTree).getChild( "dc=com" );
-        assertTrue( child instanceof DnBranchNode );
-        assertTrue( ((DnBranchNode<Partition>)child).contains( "dc=example" ) );
+        assertTrue( partitionLookupTree.hasChildren() );
+        assertTrue( partitionLookupTree.contains( new RDN( "dc=com" ) ) );
+
+        DnNode<Partition> child = partitionLookupTree.getChild( new RDN( "dc=com" ) );
+        assertTrue( child.hasChildren() );
+        assertTrue( child.contains( new RDN( "dc=example" ) ) );
 
-        child = ((DnBranchNode<Partition>)child).getChild( "dc=example" );
-        assertEquals( "dc=example, dc=com", ((DnLeafNode<Partition>)child).getElement().getSuffix().getName() );
+        child = child.getChild( new RDN( "dc=example" ) );
+        assertEquals( "dc=example, dc=com", child.getElement().getSuffix().getName() );
     }
 
 
@@ -75,66 +73,36 @@ public class PartitionTreeTest
     @Test public void testNewPartitionTree2Nodes() throws LdapException
     {
         /** A structure to hold all the partitions */
-        DnBranchNode<Partition> partitionLookupTree = new DnBranchNode<Partition>();
-        
+        DnNode<Partition> partitionLookupTree = new DnNode<Partition>();
+
         DN suffix1 = new DN( "dc=example, dc=com" );
         Partition partition1 = new JdbmPartition();
         partition1.setSuffix( suffix1 );
-        
+
         partitionLookupTree.add( suffix1, partition1 );
-        
+
         DN suffix2 = new DN( "ou=system" );
         Partition partition2 = new JdbmPartition();
         partition2.setSuffix( suffix2 );
-        
+
         partitionLookupTree.add( suffix2, partition2 );
 
         assertNotNull( partitionLookupTree );
-        assertTrue( partitionLookupTree instanceof DnBranchNode );
-        assertTrue( ((DnBranchNode<Partition>)partitionLookupTree).contains( "ou=system" ) );
-        assertTrue( ((DnBranchNode<Partition>)partitionLookupTree).contains( "dc=com" ) );
-        
-        DnNode<Partition> child = ((DnBranchNode<Partition>)partitionLookupTree).getChild( "ou=system" );
-        assertTrue( child instanceof DnLeafNode );
-        assertEquals( "ou=system", ((DnLeafNode<Partition>)child).getElement().getSuffix().getName() );
-
-        child = ((DnBranchNode<Partition>)partitionLookupTree).getChild( "dc=com" );
-        assertTrue( child instanceof DnBranchNode );
-        assertTrue( ((DnBranchNode<Partition>)child).contains( "dc=example" ) );
-        
-        child = ((DnBranchNode<Partition>)child).getChild( "dc=example" );
-        assertTrue( child instanceof DnLeafNode );
-        assertEquals( "dc=example, dc=com", ((DnLeafNode<Partition>)child).getElement().getSuffix().getName() );
-    }
-
-
-    /**
-     * Test the addition of a two overlapping partitions
-     */
-    @Test public void testNewPartitionTree2OverlapingNodes() throws LdapException
-    {
-        /** A structure to hold all the partitions */
-        DnBranchNode<Partition> partitionLookupTree = new DnBranchNode<Partition>();
-        
-        DN suffix1 = new DN( "dc=com" );
-        Partition partition1 = new JdbmPartition();
-        partition1.setSuffix( suffix1 );
-        
-        partitionLookupTree.add( suffix1, partition1 );
-        
-        DN suffix2 = new DN( "dc=example, dc=com" );
-        Partition partition2 = new JdbmPartition();
-        partition2.setSuffix( suffix2 );
-        
-        try
-        {
-            partitionLookupTree.add( suffix2, partition2 );
-            fail();
-        }
-        catch ( LdapException ne )
-        {
-            assertTrue( true );
-        }
+        assertTrue( partitionLookupTree.hasChildren() );
+        assertTrue( partitionLookupTree.contains( new RDN( "ou=system" ) ) );
+        assertTrue( partitionLookupTree.contains( new RDN( "dc=com" ) ) );
+
+        DnNode<Partition> child = partitionLookupTree.getChild( new RDN( "ou=system" ) );
+        assertTrue( child.isLeaf() );
+        assertEquals( "ou=system", child.getElement().getSuffix().getName() );
+
+        child = partitionLookupTree.getChild( new RDN( "dc=com" ) );
+        assertTrue( child.hasChildren() );
+        assertTrue( child.contains( new RDN( "dc=example" ) ) );
+
+        child = child.getChild( new RDN( "dc=example" ) );
+        assertTrue( child.isLeaf() );
+        assertEquals( "dc=example, dc=com", child.getElement().getSuffix().getName() );
     }
 
 
@@ -144,39 +112,39 @@ public class PartitionTreeTest
     @Test public void testNewPartitionTree2NodesWithSameRoot() throws LdapException
     {
         /** A structure to hold all the partitions */
-        DnBranchNode<Partition> partitionLookupTree = new DnBranchNode<Partition>();
-        
+        DnNode<Partition> partitionLookupTree = new DnNode<Partition>();
+
         DN suffix1 = new DN( "dc=example1, dc=com" );
         Partition partition1 = new JdbmPartition();
         partition1.setSuffix( suffix1 );
-        
+
         partitionLookupTree.add( suffix1, partition1 );
-        
+
         DN suffix2 = new DN( "dc=example2, dc=com" );
         Partition partition2 = new JdbmPartition();
         partition2.setSuffix( suffix2 );
-        
+
         partitionLookupTree.add( suffix2, partition2 );
 
         assertNotNull( partitionLookupTree );
-        
-        assertTrue( partitionLookupTree instanceof DnBranchNode );
-        assertTrue( ((DnBranchNode<Partition>)partitionLookupTree).contains( "dc=com" ) );
-        
-        DnNode<Partition> child = ((DnBranchNode<Partition>)partitionLookupTree).getChild( "dc=com" );
-        assertTrue( child instanceof DnBranchNode );
-
-        child = ((DnBranchNode<Partition>)partitionLookupTree).getChild( "dc=com" );
-        assertTrue( child instanceof DnBranchNode );
-        assertTrue( ((DnBranchNode<Partition>)child).contains( "dc=example1" ) );
-        assertTrue( ((DnBranchNode<Partition>)child).contains( "dc=example2" ) );
-        
-        DnNode<Partition> child1 = ((DnBranchNode<Partition>)child).getChild( "dc=example1" );
-        assertTrue( child1 instanceof DnLeafNode );
-        assertEquals( "dc=example1, dc=com", ((DnLeafNode<Partition>)child1).getElement().getSuffix().getName() );
-
-        DnNode<Partition> child2 = ((DnBranchNode<Partition>)child).getChild( "dc=example1" );
-        assertTrue( child2 instanceof DnLeafNode );
-        assertEquals( "dc=example1, dc=com", ((DnLeafNode<Partition>)child2).getElement().getSuffix().getName() );
+
+        assertTrue( partitionLookupTree.hasChildren() );
+        assertTrue( partitionLookupTree.contains( new RDN( "dc=com" ) ) );
+
+        DnNode<Partition> child = partitionLookupTree.getChild( new RDN( "dc=com" ) );
+        assertTrue( child.hasChildren() );
+
+        child = partitionLookupTree.getChild( new RDN( "dc=com" ) );
+        assertTrue( child.hasChildren() );
+        assertTrue( child.contains( new RDN( "dc=example1" ) ) );
+        assertTrue( child.contains( new RDN( "dc=example2" ) ) );
+
+        DnNode<Partition> child1 = child.getChild( new RDN( "dc=example1" ) );
+        assertTrue( child1.isLeaf() );
+        assertEquals( "dc=example1, dc=com", child1.getElement().getSuffix().getName() );
+
+        DnNode<Partition> child2 = child.getChild( new RDN( "dc=example1" ) );
+        assertTrue( child2.isLeaf() );
+        assertEquals( "dc=example1, dc=com", child2.getElement().getSuffix().getName() );
     }
 }

Modified: directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/subtree/AdministrativeRole.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/subtree/AdministrativeRole.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/subtree/AdministrativeRole.java (original)
+++ directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/subtree/AdministrativeRole.java Wed Aug  4 14:53:22 2010
@@ -22,9 +22,10 @@ package org.apache.directory.shared.ldap
 import org.apache.directory.shared.ldap.util.StringTools;
 
 /**
-*
-* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
-*/
+ * The Administrative roles
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
 public enum AdministrativeRole
 {
     /** The AutonomousArea role */

Modified: directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/tree/DnNode.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/tree/DnNode.java?rev=982272&r1=982271&r2=982272&view=diff
==============================================================================
--- directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/tree/DnNode.java (original)
+++ directory/shared/trunk/ldap/src/main/java/org/apache/directory/shared/ldap/util/tree/DnNode.java Wed Aug  4 14:53:22 2010
@@ -6,44 +6,694 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.ldap.util.tree;
 
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.naming.NamingException;
+
+import org.apache.directory.shared.ldap.exception.LdapException;
+import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException;
+import org.apache.directory.shared.ldap.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.name.DN;
+import org.apache.directory.shared.ldap.name.RDN;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 
 /**
- * An interface for nodes in a tree designed to quickly lookup hierarchical DN.
- * Branch nodes in this tree contain other nodes.  Leaf nodes in the tree
- * contain a reference to an object  whose suffix is the path through the 
+ * An class for nodes in a tree designed to quickly lookup hierarchical DN.
+ * Branch nodes in this tree refers to child nodes. Leaf nodes in the tree
+ * don't have any children. <br/>
+ * A node may cotain a reference to an object whose suffix is the path through the
  * nodes of the tree from the root.
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public interface DnNode<N>
+public class DnNode<N>
 {
+    /** The logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DnNode.class );
+
+    /** The stored element */
+    private N element;
+
+    /** The node's key */
+    private RDN rdn;
+
+    /** The node's DN */
+    private DN dn;
+
+    /** The node's depth in the tree */
+    private int depth;
+
+    /** The parent, if any */
+    private DnNode<N> parent;
+
+    /** Stores the list of all the descendant */
+    private Map<RDN, DnNode<N>> children;
+
+    //-------------------------------------------------------------------------
+    // Helper methods
+    //-------------------------------------------------------------------------
+    /**
+     * Check that the DN is not null
+     */
+    private void checkDn( DN dn ) throws LdapException
+    {
+        if ( ( dn == null ) || dn.isEmpty() )
+        {
+            String message = "Cannot process an empty DN";
+            LOG.error( message );
+            throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, message );
+        }
+    }
+
+    /**
+     * Create a new DnNode, recursively creating all the intermediate nodes.
+     */
+    private DnNode<N> createNode( DN dn, N element, int nbRdns ) throws LdapException
+    {
+        checkDn( dn );
+
+        DnNode<N> rootNode = null;
+
+        // No parent : add from the current position
+        for ( RDN rdn : dn )
+        {
+            if ( nbRdns == 0 )
+            {
+                break;
+            }
+
+            if ( rootNode == null )
+            {
+                // Create the new top node
+                DnNode<N> node = new DnNode<N>( element );
+                node.rdn = rdn;
+                node.dn = dn;
+                node.depth = dn.size() + depth;
+
+                rootNode = node;
+            }
+            else
+            {
+                DnNode<N> node = new DnNode<N>();
+                node.rdn = rdn;
+                node.dn = rootNode.dn.getParent();
+                node.depth = node.dn.size() + depth;
+                rootNode.parent = node;
+                node.children.put( rootNode.rdn, rootNode );
+                rootNode = node;
+            }
+
+            nbRdns--;
+        }
+
+        return rootNode;
+    }
+
+
+    /**
+     * Creates a new instance of DnNode.
+     */
+    public DnNode()
+    {
+        children = new ConcurrentHashMap<RDN, DnNode<N>>();
+        dn = DN.EMPTY_DN;
+        rdn = RDN.EMPTY_RDN;
+    }
+
+
+    /**
+     * Creates a new instance of DnNode.
+     *
+     * @param element the element to store
+     */
+    public DnNode( N element )
+    {
+        this.element = element;
+        children = new ConcurrentHashMap<RDN, DnNode<N>>();
+    }
+
+
+    /**
+     * Creates a new instance of DnNode.
+     *
+     * @param element the element to store
+     */
+    public DnNode( DN dn, N element )
+    {
+        if ( ( dn == null ) || ( dn.isEmpty() ) )
+        {
+            children = new ConcurrentHashMap<RDN, DnNode<N>>();
+            this.dn = DN.EMPTY_DN;
+
+            return;
+        }
+
+        try
+        {
+            DnNode<N> rootNode = createNode( dn, element, dn.size() );
+
+            // Now copy back the created node into this
+            this.children = rootNode.children;
+            this.depth = rootNode.depth;
+            this.dn = rootNode.dn;
+            this.element = rootNode.element;
+            this.rdn = rootNode.rdn;
+            this.parent = null;
+        }
+        catch ( LdapException le )
+        {
+            // Special cas e: the DN is empty, this is not allowed
+            throw new IllegalArgumentException( le.getMessage() );
+        }
+    }
+
+
     /**
      * Tells if the implementation is a leaf node. If it's a branch node
      * then false is returned.
      *
      * @return <code>true</code> if the class is a leaf node, false otherwise.
      */
-    boolean isLeaf();
-    
-    
+    public boolean isLeaf()
+    {
+        return !hasChildren();
+    }
+
+
+    /**
+     * Tells if the implementation is a leaf node. If it's a branch node
+     * then false is returned.
+     *
+     * @param dn The DN we want to check
+     * @return <code>true</code> if this is a leaf node, false otherwise.
+     */
+    public boolean isLeaf( DN dn )
+    {
+        DnNode<N> node = getNode( dn );
+
+        if ( node == null )
+        {
+            return false;
+        }
+
+        return node.children.size() == 0;
+    }
+
+
     /**
      * Returns the number of entries under this node. It includes
-     * the node itself, plus the sum of all it children and descendents.
+     * the node itself, plus the number of all it children and descendants.
      *
      * @return The number of descendents
      */
-    int size();
+    public int size()
+    {
+        // The node itself
+        int size = 1;
+
+        // Iterate through the children if any
+        if ( children.size() !=0 )
+        {
+            for ( DnNode<N> node : children.values() )
+            {
+                size += node.size();
+            }
+        }
+
+        return size;
+    }
+
+
+    /**
+     * @return Return the stored element, if any
+     */
+    public N getElement()
+    {
+        return element;
+    }
+
+
+    /**
+     * @return Return the stored element, if any
+     * @param dn The DN we want to get the element for
+     */
+    public N getElement( DN dn )
+    {
+        DnNode<N> node = getNode( dn );
+
+        if ( node == null )
+        {
+            return null;
+        }
+
+        return node.element;
+    }
+
+
+    /**
+     * @return True if the Node stores an element. BranchNode may not hold any
+     * element.
+     */
+    public boolean hasElement()
+    {
+        return element != null;
+    }
+
+
+    /**
+     * @return True if the Node stores an element. BranchNode may not hold any
+     * element.
+     * @param dn The DN we want to get the element for
+     */
+    public boolean hasElement( DN dn )
+    {
+        DnNode<N> node = getNode( dn );
+
+        if ( node == null )
+        {
+            return false;
+        }
+
+        return node.element != null;
+    }
+
+
+    /**
+     * Tells if the current DnNode has some children or not
+     *
+     * @return <code>true</code> if the node has some children
+     */
+    public boolean hasChildren()
+    {
+        return ( children != null ) && children.size() != 0;
+    }
+
+
+    /**
+     * Tells if a node has some children or not
+     *
+     * @return <code>true</code> if the node has some children
+     */
+    public boolean hasChildren( DN dn ) throws LdapException
+    {
+        checkDn( dn );
+
+        DnNode<N> node = getNode( dn );
+
+        return ( node != null ) && node.hasChildren();
+    }
+
+
+    /**
+     * @return The list of DnNode
+     */
+    public Map<RDN, DnNode<N>> getChildren()
+    {
+        return children;
+    }
+
+
+    /**
+     * @return The parent DnNode, if any
+     */
+    public DnNode<N> getParent()
+    {
+        return parent;
+    }
+
+
+    /**
+     * @return True if the current DnNode has a parent
+     */
+    public boolean hasParent()
+    {
+        return parent != null;
+    }
+
+
+    /**
+     * Tells if there is a parent for a given DN,. This parent should be a
+     * subset of the given dn.<br>
+     * For instance, if we have stored dc=acme, dc=org into the tree,
+     * the DN: ou=example, dc=acme, dc=org will have a parent
+     * <br>For the DN ou=apache, dc=org, there is no parent, so false will be returned.
+     *
+     * @param dn the normalized distinguished name to resolve to a parent
+     * @return true if there is a parent associated with the normalized dn
+     */
+    public boolean hasParent( DN dn )
+    {
+        List<RDN> rdns = dn.getRdns();
+
+        DnNode<N> currentNode = this;
+        DnNode<N> parent = null;
+
+        // Iterate through all the RDN until we find the associated partition
+        for ( int i = rdns.size() - 1; i >= 0; i-- )
+        {
+            RDN rdn = rdns.get( i );
+
+            if ( rdn.equals( currentNode.rdn ) )
+            {
+                parent = currentNode;
+            }
+            else if ( currentNode.hasChildren() )
+            {
+                currentNode = currentNode.children.get( rdn );
+
+                if ( currentNode == null )
+                {
+                    break;
+                }
+
+                parent = currentNode;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        return( parent != null );
+    }
+
+
+    /**
+     * Add a new node in the tree. The added node won't have any element.
+     *
+     * @param dn The node's DN
+     * @throws NamingException
+     */
+    public void add( DN dn ) throws LdapException
+    {
+        add( dn, null );
+    }
+
+
+    /**
+     * Add a new node in the tree. We can't add a node if its DN is empty.
+     *
+     * @param dn The node's DN
+     * @param element The element to associate with this Node. Can be null.
+     * @throws NamingException
+     */
+    public void add( DN dn, N element ) throws LdapException
+    {
+        checkDn( dn );
+
+        // We first have to find the Node which will be the parent
+        DnNode<N> parent = getNode( dn );
+
+        if ( parent == null )
+        {
+            // No parent : add a new node to the root
+            DnNode<N> childNode = createNode( dn, element, dn.size() );
+            childNode.parent = this;
+            children.put( childNode.rdn, childNode );
+        }
+        else
+        {
+            // We have a parent. Add the new node to the found parent
+            int nbRdns = dn.size() - parent.depth;
+
+            if ( nbRdns == 0 )
+            {
+                // That means the added DN is already present.
+                String message = "Cannot add a node with a DN already existing in the tree";
+                LOG.error( message );
+                throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, message );
+            }
+
+            DnNode<N> rootNode = createNode( dn, element, nbRdns );
+
+            // done. now, add the newly created tree to the parent node
+            rootNode.parent = parent;
+            parent.children.put( rootNode.rdn, rootNode );
+        }
+    }
+
+
+    /**
+     * Removes an element from the tree.
+     *
+     * @param element The element to remove
+     */
+    public void remove( DN dn ) throws LdapException
+    {
+        checkDn( dn );
+
+        // Find the parent first : we won't be able to remove
+        // a node if it's not present in the tree !
+        DnNode<N> parent = getNode( dn );
+
+        if ( parent == null )
+        {
+            return;
+        }
+
+        // Now, check that this parent has the same DN than the one
+        // we gave and that there is no children
+        if ( ( dn.size() != parent.depth ) || parent.hasChildren() )
+        {
+            return;
+        }
+
+        // Ok, no children, same DN, let's remove what we can.
+        parent = parent.getParent();
+
+        for ( RDN rdn : dn )
+        {
+            parent.children.remove( rdn );
+
+            if ( parent.children.size() > 0 )
+            {
+                // We have to stop here, because the parent's node is shared with other Node.
+                break;
+            }
+
+            parent = parent.getParent();
+        }
+    }
+
+
+    /**
+     * Tells if the current DnBranchNode contains another node associated
+     * with an rdn.
+     *
+     * @param rdn The name we are looking for
+     * @return <code>true</code> if the tree instance contains this name
+     */
+    public boolean contains( RDN rdn )
+    {
+        return children.containsKey( rdn );
+    }
+
+
+    /**
+     * Get's a child using an rdn string.
+     *
+     * @param rdn the rdn to use as the node key
+     * @return the child node corresponding to the rdn.
+     */
+    public DnNode<N> getChild( RDN rdn )
+    {
+        if ( children.containsKey( rdn ) )
+        {
+            return children.get( rdn );
+        }
+
+        return null;
+    }
+
+
+    /**
+     * @return The Node's RDN
+     */
+    public RDN getRdn()
+    {
+        return rdn;
+    }
+
+
+    /**
+     * Get the parent element of a given DN, if present in the tree. This parent should be a
+     * subset of the given dn.<br>
+     * For instance, if we have stored dc=acme, dc=org into the tree,
+     * the DN: ou=example, dc=acme, dc=org will have a parent, and
+     * dc=acme, dc=org will be returned.
+     * <br>For the DN ou=apache, dc=org, there is no parent, so null will be returned.
+     *
+     * @param dn the normalized distinguished name to resolve to a parent
+     * @return the parent associated with the normalized dn
+     *
+    public N getParentElement( DN dn )
+    {
+        List<RDN> rdns = dn.getRdns();
+
+        DnNode<N> currentNode = this;
+        DnNode<N> parent = null;
+
+        // Iterate through all the RDN until we find the associated partition
+        for ( int i = rdns.size() - 1; i >= 0; i-- )
+        {
+            if ( currentNode == null )
+            {
+                // We can stop here : there is no more node in the tree
+                break;
+            }
+
+            RDN rdn = rdns.get( i );
+
+            if ( currentNode.rdn.equals( rdn ) )
+            {
+                parent = currentNode;
+                currentNode = children.get( rdn );
+                continue;
+            }
+
+            break;
+        }
+
+        if ( parent != null )
+        {
+            return parent.getElement();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    /**
+     * Get the Node for a given DN, if present in the tree.<br>
+     * For instance, if we have stored dc=acme, dc=org into the tree,
+     * the DN: ou=example, dc=acme, dc=org will have a parent, and
+     * dc=acme, dc=org will be returned.
+     * <br>For the DN ou=apache, dc=org, there is no parent, so null will be returned.
+     *
+     * @param dn the normalized distinguished name to resolve to a parent
+     * @return the Node associated with the normalized dn
+     */
+    public DnNode<N> getNode( DN dn )
+    {
+        List<RDN> rdns = dn.getRdns();
+
+        DnNode<N> currentNode = this;
+        DnNode<N> parent = null;
+
+        // Iterate through all the RDN until we find the associated partition
+        for ( int i = rdns.size() - 1; i >= 0; i-- )
+        {
+            RDN rdn = rdns.get( i );
+
+            if ( rdn.equals( currentNode.rdn ) )
+            {
+                parent = currentNode;
+            }
+            else if ( currentNode.hasChildren() )
+            {
+                currentNode = currentNode.children.get( rdn );
+
+                if ( currentNode == null )
+                {
+                    break;
+                }
+
+                parent = currentNode;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        if ( parent != null )
+        {
+            return parent;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+    private String toString( String tabs )
+    {
+        if ( rdn == null )
+        {
+            return tabs;
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append( tabs );
+
+        boolean hasChildren = hasChildren();
+
+        if ( isLeaf() )
+        {
+            sb.append( "Leaf[" ).append( rdn ).append( "]: " ).append( "'" ).append( element ).append( "'" );
+            return sb.toString();
+        }
+
+        sb.append( "Branch[" ).append( rdn ).append( "]: " );
+
+        if ( element != null )
+        {
+            sb.append( "'" ).append( element ).append( "'" );
+        }
+
+        tabs += "    ";
+
+        sb.append( '\n' );
+
+        boolean isFirst = true;
+
+        if ( hasChildren )
+        {
+            for ( RDN rdn : children.keySet() )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.append( "\n" );
+                }
+
+                DnNode<N> child = children.get( rdn );
+
+                sb.append( child.toString( tabs ) );
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return toString( "" );
+    }
 }



Mime
View raw message