You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2011/10/15 00:36:15 UTC

svn commit: r1183537 [5/11] - in /directory/apacheds/trunk/interceptors: admin/ admin/.settings/ authn/ authn/.settings/ authz/.settings/ changelog/ changelog/src/ changelog/src/main/ changelog/src/main/java/ changelog/src/main/java/org/ changelog/src/...

Added: directory/apacheds/trunk/interceptors/operational/src/main/java/org/apache/directory/server/core/operational/OperationalAttributeInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/operational/src/main/java/org/apache/directory/server/core/operational/OperationalAttributeInterceptor.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/operational/src/main/java/org/apache/directory/server/core/operational/OperationalAttributeInterceptor.java (added)
+++ directory/apacheds/trunk/interceptors/operational/src/main/java/org/apache/directory/server/core/operational/OperationalAttributeInterceptor.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,594 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  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. 
+ *  
+ */
+package org.apache.directory.server.core.operational;
+
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.directory.server.constants.ApacheSchemaConstants;
+import org.apache.directory.server.constants.ServerDNConstants;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.entry.ClonedServerEntry;
+import org.apache.directory.server.core.api.filtering.EntryFilter;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
+import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
+import org.apache.directory.server.core.api.interceptor.Interceptor;
+import org.apache.directory.server.core.api.interceptor.NextInterceptor;
+import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ListOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.SearchingOperationContext;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.entry.Attribute;
+import org.apache.directory.shared.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.shared.ldap.model.entry.DefaultModification;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.Modification;
+import org.apache.directory.shared.ldap.model.entry.ModificationOperation;
+import org.apache.directory.shared.ldap.model.entry.Value;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.exception.LdapNoPermissionException;
+import org.apache.directory.shared.ldap.model.exception.LdapSchemaViolationException;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Ava;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.name.Rdn;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.UsageEnum;
+import org.apache.directory.shared.util.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An {@link Interceptor} that adds or modifies the default attributes
+ * of entries. There are six default attributes for now;
+ * <tt>'creatorsName'</tt>, <tt>'createTimestamp'</tt>, <tt>'modifiersName'</tt>,
+ * <tt>'modifyTimestamp'</tt>, <tt>entryUUID</tt> and <tt>entryCSN</tt>.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OperationalAttributeInterceptor extends BaseInterceptor
+{
+    /** The LoggerFactory used by this Interceptor */
+    private static Logger LOG = LoggerFactory.getLogger( OperationalAttributeInterceptor.class );
+
+    /**
+     * the search result filter to use for collective attribute injection
+     */
+    private class OperationalAttributeDenormalizingSearchFilter implements EntryFilter
+    {
+        public boolean accept( SearchingOperationContext operation, Entry entry ) throws Exception
+        {
+            if ( operation.getSearchControls().getReturningAttributes() == null )
+            {
+                return true;
+            }
+
+            return filterDenormalized( entry );
+        }
+    }
+
+    private final EntryFilter DENORMALIZING_SEARCH_FILTER = new OperationalAttributeDenormalizingSearchFilter();
+
+    /**
+     * the database search result filter to register with filter service
+     */
+    private class OperationalAttributeSearchFilter implements EntryFilter
+    {
+        public boolean accept( SearchingOperationContext operation, Entry entry ) throws Exception
+        {
+            return operation.getSearchControls().getReturningAttributes() != null
+            || filterOperationalAttributes( entry );
+        }
+    }
+    
+    private final EntryFilter SEARCH_FILTER = new OperationalAttributeSearchFilter();
+
+    /** The subschemasubentry Dn */
+    private Dn subschemaSubentryDn;
+
+    /** The admin Dn */
+    private Dn adminDn;
+
+    /**
+     * Creates the operational attribute management service interceptor.
+     */
+    public OperationalAttributeInterceptor()
+    {
+    }
+
+
+    public void init( DirectoryService directoryService ) throws LdapException
+    {
+        super.init( directoryService );
+
+        // stuff for dealing with subentries (garbage for now)
+        Value<?> subschemaSubentry = directoryService.getPartitionNexus().getRootDSE( null ).get(
+            SchemaConstants.SUBSCHEMA_SUBENTRY_AT ).get();
+        subschemaSubentryDn = directoryService.getDnFactory().create( subschemaSubentry.getString() );
+
+        // Create the Admin Dn
+        adminDn = directoryService.getDnFactory().create( ServerDNConstants.ADMIN_SYSTEM_DN );
+    }
+
+
+    public void destroy()
+    {
+    }
+
+
+    /**
+     * Check if we have to add an operational attribute, or if the admin has injected one
+     */
+    private boolean checkAddOperationalAttribute( boolean isAdmin, Entry entry, String attribute ) throws LdapException
+    {
+        if ( entry.containsAttribute( attribute ) )
+        {
+            if ( !isAdmin )
+            {
+                // Wrong !
+                String message = I18n.err( I18n.ERR_30, attribute );
+                LOG.error( message );
+                throw new LdapNoPermissionException( message );
+            }
+            else
+            {
+                return true;
+            }
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+
+    /**
+     * Adds extra operational attributes to the entry before it is added.
+     * 
+     * We add those attributes :
+     * - creatorsName
+     * - createTimestamp
+     * - entryCSN
+     * - entryUUID 
+     */
+    public void add( NextInterceptor nextInterceptor, AddOperationContext addContext ) throws LdapException
+    {
+        String principal = getPrincipal().getName();
+
+        Entry entry = addContext.getEntry();
+
+        // If we are using replication, the below four OAs may already be present and we retain
+        // those values if the user is admin.
+        boolean isAdmin = addContext.getSession().getAuthenticatedPrincipal().getName().equals(
+            ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
+
+        // The EntryUUID attribute
+        if ( !checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.ENTRY_UUID_AT ) )
+        {
+            entry.put( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
+        }
+
+        // The EntryCSN attribute
+        if ( !checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.ENTRY_CSN_AT ) )
+        {
+            entry.put( SchemaConstants.ENTRY_CSN_AT, directoryService.getCSN().toString() );
+        }
+
+        // The CreatorsName attribute
+        if ( !checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.CREATORS_NAME_AT ) )
+        {
+            entry.put( SchemaConstants.CREATORS_NAME_AT, principal );
+        }
+
+        // The CreateTimeStamp attribute
+        if ( !checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.CREATE_TIMESTAMP_AT ) )
+        {
+            entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        }
+
+        // Now, check that the user does not add operational attributes
+        // The accessControlSubentries attribute
+        checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT );
+
+        // The CollectiveAttributeSubentries attribute
+        checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT );
+
+        // The TriggerExecutionSubentries attribute
+        checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT );
+
+        // The SubSchemaSybentry attribute
+        checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.SUBSCHEMA_SUBENTRY_AT );
+
+        nextInterceptor.add( addContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( NextInterceptor nextInterceptor, ModifyOperationContext modifyContext ) throws LdapException
+    {
+        // We must check that the user hasn't injected either the modifiersName
+        // or the modifyTimestamp operational attributes : they are not supposed to be
+        // added at this point EXCEPT in cases of replication by a admin user.
+        // If so, remove them, and if there are no more attributes, simply return.
+        // otherwise, inject those values into the list of modifications
+        List<Modification> mods = modifyContext.getModItems();
+
+        boolean isAdmin = modifyContext.getSession().getAuthenticatedPrincipal().getDn().equals( adminDn );
+
+        boolean modifierAtPresent = false;
+        boolean modifiedTimeAtPresent = false;
+        boolean entryCsnAtPresent = false;
+        
+        for ( Modification modification : mods )
+        {
+            AttributeType attributeType = modification.getAttribute().getAttributeType();
+
+            if ( attributeType.equals( MODIFIERS_NAME_AT ) )
+            {
+                if ( !isAdmin )
+                {
+                    String message = I18n.err( I18n.ERR_31 );
+                    LOG.error( message );
+                    throw new LdapSchemaViolationException( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, message );
+                }
+                else
+                {
+                    modifierAtPresent = true;
+                }
+            }
+
+            if ( attributeType.equals( MODIFY_TIMESTAMP_AT ) )
+            {
+                if ( !isAdmin )
+                {
+                    String message = I18n.err( I18n.ERR_32 );
+                    LOG.error( message );
+                    throw new LdapSchemaViolationException( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, message );
+                }
+                else
+                {
+                    modifiedTimeAtPresent = true;
+                }
+            }
+
+            if ( attributeType.equals( ENTRY_CSN_AT ) )
+            {
+                if ( !isAdmin )
+                {
+                    String message = I18n.err( I18n.ERR_32 );
+                    LOG.error( message );
+                    throw new LdapSchemaViolationException( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, message );
+                }
+                else
+                {
+                    entryCsnAtPresent = true;
+                }
+            }
+
+            if ( PWD_POLICY_STATE_ATTRIBUTE_TYPES.contains( attributeType ) && !isAdmin )
+            {
+                String message = I18n.err( I18n.ERR_32 );
+                LOG.error( message );
+                throw new LdapSchemaViolationException( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, message );
+            }
+        }
+
+        if ( !modifierAtPresent )
+        {
+            // Inject the ModifiersName AT if it's not present
+            Attribute attribute = new DefaultAttribute( MODIFIERS_NAME_AT, getPrincipal()
+                .getName() );
+
+            Modification modifiersName = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attribute );
+
+            mods.add( modifiersName );
+        }
+
+        if ( !modifiedTimeAtPresent )
+        {
+            // Inject the ModifyTimestamp AT if it's not present
+            Attribute attribute = new DefaultAttribute( MODIFY_TIMESTAMP_AT, DateUtils
+                .getGeneralizedTime() );
+
+            Modification timestamp = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attribute );
+
+            mods.add( timestamp );
+        }
+
+        if ( !entryCsnAtPresent )
+        {
+            String csn = directoryService.getCSN().toString();
+            Attribute attribute = new DefaultAttribute( ENTRY_CSN_AT, csn );
+            Modification updatedCsn = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attribute );
+            mods.add( updatedCsn );
+        }
+        
+        // Go down in the chain
+        nextInterceptor.modify( modifyContext );
+    }
+
+
+    public void rename( NextInterceptor nextInterceptor, RenameOperationContext renameContext ) throws LdapException
+    {
+        Entry entry = ( ( ClonedServerEntry ) renameContext.getEntry() ).getClonedEntry();
+        entry.put( SchemaConstants.MODIFIERS_NAME_AT, getPrincipal().getName() );
+        entry.put( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+
+        Entry modifiedEntry = renameContext.getOriginalEntry().clone();
+        modifiedEntry.put( SchemaConstants.MODIFIERS_NAME_AT, getPrincipal().getName() );
+        modifiedEntry.put( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        //modifiedEntry.setDn( renameContext.getNewDn() );
+        renameContext.setModifiedEntry( modifiedEntry );
+
+        nextInterceptor.rename( renameContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void move( NextInterceptor nextInterceptor, MoveOperationContext moveContext ) throws LdapException
+    {
+        Entry modifiedEntry = moveContext.getOriginalEntry().clone();
+        modifiedEntry.put( SchemaConstants.MODIFIERS_NAME_AT, getPrincipal().getName() );
+        modifiedEntry.put( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        modifiedEntry.setDn( moveContext.getNewDn() );
+        moveContext.setModifiedEntry( modifiedEntry );
+
+        nextInterceptor.move( moveContext );
+    }
+
+
+    public void moveAndRename( NextInterceptor nextInterceptor, MoveAndRenameOperationContext moveAndRenameContext )
+        throws LdapException
+    {
+        Entry modifiedEntry = moveAndRenameContext.getOriginalEntry().clone();
+        modifiedEntry.put( SchemaConstants.MODIFIERS_NAME_AT, getPrincipal().getName() );
+        modifiedEntry.put( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        modifiedEntry.setDn( moveAndRenameContext.getNewDn() );
+        moveAndRenameContext.setModifiedEntry( modifiedEntry );
+
+        nextInterceptor.moveAndRename( moveAndRenameContext );
+    }
+
+
+    public Entry lookup( NextInterceptor nextInterceptor, LookupOperationContext lookupContext ) throws LdapException
+    {
+        Entry result = nextInterceptor.lookup( lookupContext );
+
+        if ( lookupContext.getAttrsId() == null )
+        {
+            filterOperationalAttributes( result );
+        }
+        else if ( !lookupContext.hasAllOperational() )
+        {
+            filter( lookupContext, result );
+        }
+
+        denormalizeEntryOpAttrs( result );
+        return result;
+    }
+
+
+    public EntryFilteringCursor list( NextInterceptor nextInterceptor, ListOperationContext listContext )
+        throws LdapException
+    {
+        EntryFilteringCursor cursor = nextInterceptor.list( listContext );
+        cursor.addEntryFilter( SEARCH_FILTER );
+        return cursor;
+    }
+
+
+    public EntryFilteringCursor search( NextInterceptor nextInterceptor, SearchOperationContext searchContext )
+        throws LdapException
+    {
+        EntryFilteringCursor cursor = nextInterceptor.search( searchContext );
+
+        if ( searchContext.isAllOperationalAttributes()
+            || ( searchContext.getReturningAttributes() != null && !searchContext.getReturningAttributes().isEmpty() ) )
+        {
+            if ( directoryService.isDenormalizeOpAttrsEnabled() )
+            {
+                cursor.addEntryFilter( DENORMALIZING_SEARCH_FILTER );
+            }
+
+            return cursor;
+        }
+
+        cursor.addEntryFilter( SEARCH_FILTER );
+        return cursor;
+    }
+
+
+    /**
+     * Filters out the operational attributes within a search results attributes.  The attributes are directly
+     * modified.
+     *
+     * @param attributes the resultant attributes to filter
+     * @return true always
+     * @throws Exception if there are failures in evaluation
+     */
+    private boolean filterOperationalAttributes( Entry attributes ) throws LdapException
+    {
+        Set<AttributeType> removedAttributes = new HashSet<AttributeType>();
+
+        // Build a list of attributeType to remove
+        for ( Attribute attribute : attributes.getAttributes() )
+        {
+            AttributeType attributeType = attribute.getAttributeType();
+            
+            if ( attributeType.getUsage() != UsageEnum.USER_APPLICATIONS )
+            {
+                removedAttributes.add( attributeType );
+            }
+        }
+
+        // Now remove the attributes which are not USERs
+        for ( AttributeType attributeType : removedAttributes )
+        {
+            attributes.removeAttributes( attributeType );
+        }
+
+        return true;
+    }
+
+
+    private void filter( LookupOperationContext lookupContext, Entry entry ) throws LdapException
+    {
+        Dn dn = lookupContext.getDn();
+        List<String> ids = lookupContext.getAttrsId();
+
+        // still need to protect against returning op attrs when ids is null
+        if ( ids == null || ids.isEmpty() )
+        {
+            filterOperationalAttributes( entry );
+            return;
+        }
+
+        if ( dn.size() == 0 )
+        {
+            for ( Attribute attribute : entry.getAttributes() )
+            {
+                AttributeType attributeType = attribute.getAttributeType();
+
+                if ( !ids.contains( attributeType.getOid() ) )
+                {
+                    entry.removeAttributes( attributeType );
+                }
+            }
+        }
+
+        denormalizeEntryOpAttrs( entry );
+
+        // do nothing past here since this explicity specifies which
+        // attributes to include - backends will automatically populate
+        // with right set of attributes using ids array
+    }
+
+
+    public void denormalizeEntryOpAttrs( Entry entry ) throws LdapException
+    {
+        if ( directoryService.isDenormalizeOpAttrsEnabled() )
+        {
+            Attribute attr = entry.get( SchemaConstants.CREATORS_NAME_AT );
+
+            if ( attr != null )
+            {
+                Dn creatorsName = directoryService.getDnFactory().create( attr.getString() );
+
+                attr.clear();
+                attr.add( denormalizeTypes( creatorsName ).getName() );
+            }
+
+            attr = entry.get( SchemaConstants.MODIFIERS_NAME_AT );
+
+            if ( attr != null )
+            {
+                Dn modifiersName = directoryService.getDnFactory().create( attr.getString() );
+
+                attr.clear();
+                attr.add( denormalizeTypes( modifiersName ).getName() );
+            }
+
+            attr = entry.get( ApacheSchemaConstants.SCHEMA_MODIFIERS_NAME_AT );
+
+            if ( attr != null )
+            {
+                Dn modifiersName = directoryService.getDnFactory().create( attr.getString() );
+
+                attr.clear();
+                attr.add( denormalizeTypes( modifiersName ).getName() );
+            }
+        }
+    }
+
+
+    /**
+     * Does not create a new Dn but alters existing Dn by using the first
+     * short name for an attributeType definition.
+     * 
+     * @param dn the normalized distinguished name
+     * @return the distinuished name denormalized
+     * @throws Exception if there are problems denormalizing
+     */
+    private Dn denormalizeTypes( Dn dn ) throws LdapException
+    {
+        Dn newDn = new Dn( schemaManager );
+        int size = dn.size();
+
+        for ( int pos = 0; pos < size; pos++ )
+        {
+            Rdn rdn = dn.getRdn( size - 1 - pos );
+            
+            if ( rdn.size() == 0 )
+            {
+                newDn = newDn.add( new Rdn() );
+                continue;
+            }
+            else if ( rdn.size() == 1 )
+            {
+                String name = schemaManager.lookupAttributeTypeRegistry( rdn.getNormType() ).getName();
+                String value = rdn.getNormValue().getString();
+                newDn = newDn.add( new Rdn( name, value ) );
+                continue;
+            }
+
+            // below we only process multi-valued rdns
+            StringBuffer buf = new StringBuffer();
+
+            for ( Iterator<Ava> atavs = rdn.iterator(); atavs.hasNext(); /**/)
+            {
+                Ava atav = atavs.next();
+                String type = schemaManager.lookupAttributeTypeRegistry( rdn.getNormType() ).getName();
+                buf.append( type ).append( '=' ).append( atav.getNormValue() );
+
+                if ( atavs.hasNext() )
+                {
+                    buf.append( '+' );
+                }
+            }
+
+            newDn = newDn.add( new Rdn( buf.toString() ) );
+        }
+
+        return newDn;
+    }
+
+
+    private boolean filterDenormalized( Entry entry ) throws Exception
+    {
+        denormalizeEntryOpAttrs( entry );
+        return true;
+    }
+}
\ No newline at end of file

Propchange: directory/apacheds/trunk/interceptors/referral/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Oct 14 22:36:08 2011
@@ -0,0 +1,10 @@
+.project
+.classpath
+.settings
+eclipse-classes
+*.log
+*.iml
+*.ipr
+dependency-reduced-pom.xml
+META-INF
+

Added: directory/apacheds/trunk/interceptors/referral/pom.xml
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/referral/pom.xml?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/referral/pom.xml (added)
+++ directory/apacheds/trunk/interceptors/referral/pom.xml Fri Oct 14 22:36:08 2011
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.server</groupId>
+    <artifactId>apacheds-interceptors</artifactId>
+    <version>2.0.0-M4-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>apacheds-interceptors-referral</artifactId>
+  <name>ApacheDS Referral Interceptor</name>
+  <packaging>jar</packaging>
+
+  <description>
+    Referral interceptor
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-shared</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-client-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-codec-standalone</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-codec-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-aci</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-trigger</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-util</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-model</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-schema-data</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-util</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>bouncycastle</groupId>
+      <artifactId>bcprov-jdk15</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>net.sf.ehcache</groupId>
+      <artifactId>ehcache-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-codec</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration> 
+          <systemPropertyVariables>
+            <workingDirectory>${basedir}/target/server-work</workingDirectory>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+        <excludes>
+          <exclude>**/*.gif</exclude>
+        </excludes>
+      </resource>
+    </resources>
+  </build>
+</project>
+

Added: directory/apacheds/trunk/interceptors/referral/src/main/java/org/apache/directory/server/core/referral/ReferralInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/referral/src/main/java/org/apache/directory/server/core/referral/ReferralInterceptor.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/referral/src/main/java/org/apache/directory/server/core/referral/ReferralInterceptor.java (added)
+++ directory/apacheds/trunk/interceptors/referral/src/main/java/org/apache/directory/server/core/referral/ReferralInterceptor.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,408 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  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. 
+ *  
+ */
+package org.apache.directory.server.core.referral;
+
+
+import javax.naming.Context;
+
+import org.apache.directory.server.core.shared.ReferralManagerImpl;
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.ReferralManager;
+import org.apache.directory.server.core.api.entry.ClonedServerEntry;
+import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
+import org.apache.directory.server.core.api.interceptor.NextInterceptor;
+import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
+import org.apache.directory.server.core.api.partition.PartitionNexus;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.entry.Attribute;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.StringValue;
+import org.apache.directory.shared.ldap.model.entry.Value;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.exception.LdapURLEncodingException;
+import org.apache.directory.shared.ldap.model.message.SearchScope;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.url.LdapUrl;
+import org.apache.directory.shared.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An service which is responsible referral handling behavoirs.  It manages 
+ * referral handling behavoir when the {@link Context#REFERRAL} is implicitly
+ * or explicitly set to "ignore", when set to "throw" and when set to "follow". 
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ReferralInterceptor extends BaseInterceptor
+{
+    private static final Logger LOG = LoggerFactory.getLogger( ReferralInterceptor.class );
+
+    private PartitionNexus nexus;
+
+    /** The referralManager */
+    private ReferralManager referralManager;
+
+    /** A normalized form for the SubschemaSubentry Dn */
+    private Dn subschemaSubentryDn;
+
+    static private void checkRefAttributeValue( Value<?> value ) throws LdapException, LdapURLEncodingException
+    {
+        StringValue ref = (StringValue) value;
+
+        String refVal = ref.getString();
+
+        LdapUrl ldapUrl = new LdapUrl( refVal );
+
+        // We have a LDAP URL, we have to check that :
+        // - we don't have scope specifier
+        // - we don't have filters
+        // - we don't have attribute description list
+        // - we don't have extensions
+        // - the Dn is not empty
+
+        if ( ldapUrl.getScope() != SearchScope.OBJECT )
+        {
+            // This is the default value if we don't have any scope
+            // Let's assume that it's incorrect if we get something
+            // else in the LdapURL
+            String message = I18n.err( I18n.ERR_36 );
+            LOG.error( message );
+            throw new LdapException( message );
+        }
+
+        if ( !Strings.isEmpty(ldapUrl.getFilter()) )
+        {
+            String message = I18n.err( I18n.ERR_37 );
+            LOG.error( message );
+            throw new LdapException( message );
+        }
+
+        if ( ( ldapUrl.getAttributes() != null ) && ( ldapUrl.getAttributes().size() != 0 ) )
+        {
+            String message = I18n.err( I18n.ERR_38 );
+            LOG.error( message );
+            throw new LdapException( message );
+        }
+
+        if ( ( ldapUrl.getExtensions() != null ) && ( ldapUrl.getExtensions().size() != 0 ) )
+        {
+            String message = I18n.err( I18n.ERR_39 );
+            LOG.error( message );
+            throw new LdapException( message );
+        }
+
+        if ( ( ldapUrl.getExtensions() != null ) && ( ldapUrl.getExtensions().size() != 0 ) )
+        {
+            String message = I18n.err( I18n.ERR_40 );
+            LOG.error( message );
+            throw new LdapException( message );
+        }
+
+        Dn dn = ldapUrl.getDn();
+
+        if ( ( dn == null ) || dn.isEmpty() )
+        {
+            String message = I18n.err( I18n.ERR_41 );
+            LOG.error( message );
+            throw new LdapException( message );
+        }
+    }
+
+
+    // This will suppress PMD.EmptyCatchBlock warnings in this method
+    @SuppressWarnings("PMD.EmptyCatchBlock")
+    static private boolean isReferral( Entry entry ) throws LdapException
+    {
+        // Check that the entry is not null, otherwise return FALSE.
+        // This is typically to cover the case where the entry has not 
+        // been added into the context because it does not exists.
+        if ( entry == null )
+        {
+            return false;
+        }
+
+        Attribute oc = entry.get( OBJECT_CLASS_AT );
+
+        if ( oc == null )
+        {
+            LOG.warn( "could not find objectClass attribute in entry: " + entry );
+            return false;
+        }
+
+        if ( !oc.contains( SchemaConstants.REFERRAL_OC ) )
+        {
+            return false;
+        }
+        else
+        {
+            // We have a referral ObjectClass, let's check that the ref is
+            // valid, accordingly to the RFC
+
+            // Get the 'ref' attributeType
+            Attribute refAttr = entry.get( SchemaConstants.REF_AT );
+
+            if ( refAttr == null )
+            {
+                // very unlikely, as we have already checked the entry in SchemaInterceptor
+                String message = I18n.err( I18n.ERR_42 );
+                LOG.error( message );
+                throw new LdapException( message );
+            }
+
+            for ( Value<?> value : refAttr )
+            {
+                try
+                {
+                    checkRefAttributeValue( value );
+                }
+                catch ( LdapURLEncodingException luee )
+                {
+                    // Either the URL is invalid, or it's not a LDAP URL.
+                    // we will just ignore this LdapURL.
+                }
+            }
+
+            return true;
+        }
+    }
+
+
+    public void init( DirectoryService directoryService ) throws LdapException
+    {
+        super.init( directoryService );
+
+        nexus = directoryService.getPartitionNexus();
+
+        // Initialize the referralManager
+        referralManager = new ReferralManagerImpl( directoryService );
+        directoryService.setReferralManager( referralManager );
+
+        Value<?> subschemaSubentry = nexus.getRootDSE( null ).get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ).get();
+        subschemaSubentryDn = directoryService.getDnFactory().create( subschemaSubentry.getString() );
+    }
+
+
+    /**
+     * Add an entry into the server. We have 3 cases :
+     * (1) The entry does not have any parent referral and is not a referral itself
+     * (2) The entry does not have any parent referral and is a referral itself
+     * (3) The entry has a parent referral
+     * 
+     * Case (1) is easy : we inject the entry into the server and we are done.
+     * Case (2) is the same as case (1), but we have to update the referral manager.
+     * Case (3) is handled by the LdapProcotol handler, as we have to return a 
+     * LdapResult containing a list of this entry's parent's referrals URL, if the 
+     * ManageDSAIT control is not present, or the parent's entry if the control 
+     * is present. 
+     * 
+     * Of course, if the entry already exists, nothing will be done, as we will get an
+     * entryAlreadyExists error.
+     *  
+     */
+    public void add( NextInterceptor next, AddOperationContext addContext ) throws LdapException
+    {
+        Entry entry = addContext.getEntry();
+
+        // Check if the entry is a referral itself
+        boolean isReferral = isReferral( entry );
+
+        // We add the entry into the server
+        next.add( addContext );
+
+        // If the addition is successful, we update the referralManager 
+        if ( isReferral )
+        {
+            // We have to add it to the referralManager
+            referralManager.lockWrite();
+
+            referralManager.addReferral( entry );
+
+            referralManager.unlock();
+        }
+    }
+
+
+    /**
+     * Delete an entry in the server. We have 4 cases :
+     * (1) the entry is not a referral and does not have a parent referral
+     * (2) the entry is not a referral but has a parent referral
+     * (3) the entry is a referral
+     * 
+     * Case (1) is handled by removing the entry from the server
+     * In case (2), we return an exception build using the parent referral 
+     * For case(3), we remove the entry from the server and remove the referral
+     * from the referral manager.
+     * 
+     * If the entry does not exist in the server, we will get a NoSuchObject error
+     */
+    public void delete( NextInterceptor next, DeleteOperationContext deleteContext ) throws LdapException
+    {
+        // First delete the entry into the server
+        next.delete( deleteContext );
+
+        Entry entry = deleteContext.getEntry();
+
+        // Check if the entry exists and is a referral itself
+        // If so, we have to update the referralManager
+        if ( ( entry != null ) && isReferral( entry ) )
+        {
+            // We have to remove it from the referralManager
+            referralManager.lockWrite();
+
+            referralManager.removeReferral( entry );
+
+            referralManager.unlock();
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     **/
+    public void move( NextInterceptor next, MoveOperationContext moveContext ) throws LdapException
+    {
+        Dn newDn = moveContext.getNewDn();
+
+        // Check if the entry is a referral itself
+        boolean isReferral = isReferral( moveContext.getOriginalEntry() );
+
+        next.move( moveContext );
+
+        if ( isReferral )
+        {
+            // Update the referralManager
+            referralManager.lockWrite();
+
+            referralManager.addReferral( moveContext.getModifiedEntry() );
+            referralManager.removeReferral( moveContext.getOriginalEntry() );
+
+            referralManager.unlock();
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     **/
+    public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
+    {
+        // Check if the entry is a referral itself
+        boolean isReferral = isReferral( moveAndRenameContext.getOriginalEntry() );
+
+        next.moveAndRename( moveAndRenameContext );
+
+        if ( isReferral )
+        {
+            // Update the referralManager
+            Entry newEntry = moveAndRenameContext.getModifiedEntry();
+
+            referralManager.lockWrite();
+
+            referralManager.addReferral( newEntry );
+            referralManager.removeReferral( moveAndRenameContext.getOriginalEntry() );
+
+            referralManager.unlock();
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     **/
+    public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws LdapException
+    {
+        // Check if the entry is a referral itself
+        boolean isReferral = isReferral( renameContext.getOriginalEntry() );
+
+        next.rename( renameContext );
+
+        if ( isReferral )
+        {
+            // Update the referralManager
+            LookupOperationContext lookupContext = new LookupOperationContext( renameContext.getSession(), renameContext
+                .getNewDn() );
+            lookupContext.setAttrsId( SchemaConstants.ALL_ATTRIBUTES_ARRAY );
+
+            Entry newEntry = nexus.lookup( lookupContext );
+
+            referralManager.lockWrite();
+
+            referralManager.addReferral( newEntry );
+            referralManager.removeReferral( ((ClonedServerEntry)renameContext.getEntry()).getOriginalEntry() );
+
+            referralManager.unlock();
+        }
+    }
+
+
+    /**
+     * Modify an entry in the server.
+     */
+    public void modify( NextInterceptor next, ModifyOperationContext modifyContext ) throws LdapException
+    {
+        Dn dn = modifyContext.getDn();
+
+        // handle a normal modify without following referrals
+        next.modify( modifyContext );
+
+        // Check if we are trying to modify the schema or the rootDSE,
+        // if so, we don't modify the referralManager
+        if ( dn.isEmpty() || dn.equals( subschemaSubentryDn ) )
+        {
+            // Do nothing
+            return;
+        }
+
+        // Update the referralManager. We have to read the entry again
+        // as it has been modified, before updating the ReferralManager
+        // TODO: this can be spare, as we already have the altered entry
+        // into the opContext, but for an unknow reason, this will fail
+        // on eferral tests...
+        LookupOperationContext lookupContext = new LookupOperationContext( modifyContext.getSession(), dn );
+        lookupContext.setAttrsId( SchemaConstants.ALL_ATTRIBUTES_ARRAY );
+
+        Entry newEntry = nexus.lookup( lookupContext );
+
+        // Update the referralManager.
+        // Check that we have the entry, just in case
+        // TODO : entries should be locked until the operation is done on it.
+        if ( newEntry != null )
+        {
+            referralManager.lockWrite();
+
+            if ( referralManager.isReferral( newEntry.getDn() ) )
+            {
+                referralManager.removeReferral( modifyContext.getEntry() );
+                referralManager.addReferral( newEntry );
+            }
+
+            referralManager.unlock();
+        }
+    }
+}

Propchange: directory/apacheds/trunk/interceptors/schema/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Oct 14 22:36:08 2011
@@ -0,0 +1,11 @@
+.project
+.classpath
+.settings
+eclipse-classes
+*.log
+*.iml
+*.ipr
+dependency-reduced-pom.xml
+META-INF
+
+

Added: directory/apacheds/trunk/interceptors/schema/pom.xml
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/schema/pom.xml?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/schema/pom.xml (added)
+++ directory/apacheds/trunk/interceptors/schema/pom.xml Fri Oct 14 22:36:08 2011
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.server</groupId>
+    <artifactId>apacheds-interceptors</artifactId>
+    <version>2.0.0-M4-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>apacheds-interceptors-schema</artifactId>
+  <name>ApacheDS Schema Interceptor</name>
+  <packaging>jar</packaging>
+
+  <description>
+    Schema interceptor
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-shared</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-interceptors-authn</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-interceptors-exception</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-interceptors-normalization</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-client-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-codec-standalone</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-codec-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-aci</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-trigger</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-util</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-model</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-schema-data</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-util</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>bouncycastle</groupId>
+      <artifactId>bcprov-jdk15</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>net.sf.ehcache</groupId>
+      <artifactId>ehcache-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-codec</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration> 
+          <systemPropertyVariables>
+            <workingDirectory>${basedir}/target/server-work</workingDirectory>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+        <excludes>
+          <exclude>**/*.gif</exclude>
+        </excludes>
+      </resource>
+    </resources>
+  </build>
+</project>
+

Added: directory/apacheds/trunk/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/AttributesFactory.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/AttributesFactory.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/AttributesFactory.java (added)
+++ directory/apacheds/trunk/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/AttributesFactory.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,420 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  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. 
+ *  
+ */
+package org.apache.directory.server.core.schema; 
+
+
+import java.util.List;
+
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.shared.ldap.model.constants.MetaSchemaConstants;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.entry.DefaultEntry;
+import org.apache.directory.shared.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.shared.ldap.model.entry.Attribute;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.DITContentRule;
+import org.apache.directory.shared.ldap.model.schema.DITStructureRule;
+import org.apache.directory.shared.ldap.model.schema.LdapComparator;
+import org.apache.directory.shared.ldap.model.schema.LdapSyntax;
+import org.apache.directory.shared.ldap.model.schema.MatchingRule;
+import org.apache.directory.shared.ldap.model.schema.MatchingRuleUse;
+import org.apache.directory.shared.ldap.model.schema.NameForm;
+import org.apache.directory.shared.ldap.model.schema.Normalizer;
+import org.apache.directory.shared.ldap.model.schema.ObjectClass;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+import org.apache.directory.shared.ldap.model.schema.SchemaObject;
+import org.apache.directory.shared.ldap.model.schema.SyntaxChecker;
+import org.apache.directory.shared.ldap.model.schema.registries.Schema;
+import org.apache.directory.shared.util.DateUtils;
+
+
+/**
+ * A factory that generates an entry using the meta schema for schema 
+ * elements.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class AttributesFactory
+{
+    public Entry getAttributes( SchemaObject obj, Schema schema, SchemaManager schemaManager ) throws LdapException
+    {
+        if ( obj instanceof LdapSyntax )
+        {
+            return getAttributes( ( LdapSyntax ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof MatchingRule )
+        {
+            return getAttributes( ( MatchingRule ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof AttributeType )
+        {
+            return getAttributes( ( AttributeType ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof ObjectClass )
+        {
+            return getAttributes( ( ObjectClass ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof MatchingRuleUse )
+        {
+            return getAttributes( ( MatchingRuleUse ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof DITStructureRule )
+        {
+            return getAttributes( ( DITStructureRule ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof DITContentRule )
+        {
+            return getAttributes( ( DITContentRule ) obj, schema, schemaManager );
+        }
+        else if ( obj instanceof NameForm )
+        {
+            return getAttributes( ( NameForm ) obj, schema, schemaManager );
+        }
+        
+        throw new IllegalArgumentException( I18n.err( I18n.ERR_698, obj.getClass() ) );
+    }
+    
+    
+    public Entry getAttributes( Schema schema, SchemaManager schemaManager ) throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_SCHEMA_OC );
+        entry.put( SchemaConstants.CN_AT, schema.getSchemaName() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        
+        if ( schema.isDisabled() )
+        {
+            entry.put( MetaSchemaConstants.M_DISABLED_AT, "TRUE" );
+        }
+        
+        String[] dependencies = schema.getDependencies();
+        
+        if ( dependencies != null && dependencies.length > 0 )
+        {
+            Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_DEPENDENCIES_AT ) );
+            
+            for ( String dependency:dependencies )
+            {
+                attr.add( dependency );
+            }
+            
+            entry.put( attr );
+        }
+        
+        return entry;
+    }
+    
+    
+    public Entry getAttributes( SyntaxChecker syntaxChecker, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_SYNTAX_CHECKER_OC );
+        entry.put( MetaSchemaConstants.M_OID_AT, syntaxChecker.getOid() );
+        entry.put( MetaSchemaConstants.M_FQCN_AT, syntaxChecker.getClass().getName() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        
+        return entry;
+    }
+
+    
+    public Entry getAttributes( LdapSyntax syntax, Schema schema, SchemaManager schemaManager ) throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_SYNTAX_OC );
+        entry.put( MetaSchemaConstants.X_HUMAN_READABLE_AT, getBoolean( syntax.isHumanReadable() ) );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        injectCommon( syntax, entry, schemaManager );
+        
+        return entry;
+    }
+
+    
+    public Entry getAttributes( String oid, Normalizer normalizer, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_NORMALIZER_OC );
+        entry.put( MetaSchemaConstants.M_OID_AT, oid );
+        entry.put( MetaSchemaConstants.M_FQCN_AT, normalizer.getClass().getName() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+    
+    public Entry getAttributes( String oid, LdapComparator<? super Object> comparator, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_COMPARATOR_OC );
+        entry.put( MetaSchemaConstants.M_OID_AT, oid );
+        entry.put( MetaSchemaConstants.M_FQCN_AT, comparator.getClass().getName() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+
+    /**
+     * 
+     * @param matchingRule
+     * @return Attributes
+     * @throws LdapException
+     */
+    public Entry getAttributes( MatchingRule matchingRule, Schema schema, SchemaManager schemaManager ) throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_MATCHING_RULE_OC );
+        entry.put( MetaSchemaConstants.M_SYNTAX_AT, matchingRule.getSyntaxOid() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        injectCommon( matchingRule, entry, schemaManager );
+        return entry;
+    }
+
+    
+    public Entry getAttributes( MatchingRuleUse matchingRuleUse, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+    
+    public Entry getAttributes( DITStructureRule dITStructureRule, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+    
+    public Entry getAttributes( DITContentRule dITContentRule, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+    
+    public Entry getAttributes( NameForm nameForm, Schema schema, SchemaManager schemaManager )
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        return entry;
+    }
+
+
+    /**
+     * <pre>
+     *    objectclass ( 1.3.6.1.4.1.18060.0.4.0.3.3
+     *       NAME 'metaAttributeType'
+     *       DESC 'meta definition of the AttributeType object'
+     *       SUP metaTop
+     *       STRUCTURAL
+     *       MUST ( m-name $ m-syntax )
+     *       MAY ( m-supAttributeType $ m-obsolete $ m-equality $ m-ordering $ 
+     *             m-substr $ m-singleValue $ m-collective $ m-noUserModification $ 
+     *             m-usage $ m-extensionAttributeType )
+     *    )
+     * </pre>
+     * 
+     * @param attributeType
+     * @return Attributes
+     * @throws LdapException
+     */
+    public Entry getAttributes( AttributeType attributeType, Schema schema, SchemaManager schemaManager ) throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC );
+        entry.put( MetaSchemaConstants.M_SYNTAX_AT, attributeType.getSyntaxOid() );
+        entry.put( MetaSchemaConstants.M_COLLECTIVE_AT, getBoolean( attributeType.isCollective() ) );
+        entry.put( MetaSchemaConstants.M_NO_USER_MODIFICATION_AT, getBoolean( ! attributeType.isUserModifiable() ) );
+        entry.put( MetaSchemaConstants.M_SINGLE_VALUE_AT, getBoolean( attributeType.isSingleValued() ) );
+        entry.put( MetaSchemaConstants.M_USAGE_AT, attributeType.getUsage().toString() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+
+        injectCommon( attributeType, entry, schemaManager );
+        
+        String superiorOid = attributeType.getSuperiorOid();
+        
+        if ( superiorOid != null )
+        {
+            entry.put( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT, superiorOid );
+        }
+        
+        if ( attributeType.getEqualityOid() != null )
+        {
+            entry.put( MetaSchemaConstants.M_EQUALITY_AT, attributeType.getEqualityOid() );
+        }
+
+        if ( attributeType.getSubstringOid() != null )
+        {
+            entry.put( MetaSchemaConstants.M_SUBSTR_AT, attributeType.getSubstringOid() );
+        }
+
+        if ( attributeType.getOrderingOid() != null )
+        {
+            entry.put( MetaSchemaConstants.M_ORDERING_AT, attributeType.getOrderingOid() );
+        }
+
+        return entry;
+    }
+
+    
+    /**
+     * Creates the attributes of an entry representing an objectClass.
+     * 
+     * <pre>
+     *  objectclass ( 1.3.6.1.4.1.18060.0.4.0.3.2
+     *      NAME 'metaObjectClass'
+     *      DESC 'meta definition of the objectclass object'
+     *      SUP metaTop
+     *      STRUCTURAL
+     *      MUST m-oid
+     *      MAY ( m-name $ m-obsolete $ m-supObjectClass $ m-typeObjectClass $ m-must $ 
+     *            m-may $ m-extensionObjectClass )
+     *  )
+     * </pre>
+     * 
+     * @param objectClass the objectClass to produce a meta schema entry for
+     * @return the attributes of the metaSchema entry representing the objectClass
+     * @throws LdapException if there are any problems
+     */
+    public Entry getAttributes( ObjectClass objectClass, Schema schema, SchemaManager schemaManager ) throws LdapException
+    {
+        Entry entry = new DefaultEntry( schemaManager );
+
+        entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_OBJECT_CLASS_OC );
+        entry.put( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT, objectClass.getType().toString() );
+        entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() );
+        entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
+        
+        injectCommon( objectClass, entry, schemaManager );
+
+        // handle the superior objectClasses 
+        if ( objectClass.getSuperiorOids() != null && objectClass.getSuperiorOids().size() != 0 )
+        {
+            Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT ) );
+            
+            for ( String superior:objectClass.getSuperiorOids() )
+            {
+                attr.add( superior ); 
+            }
+            
+            entry.put( attr );
+        }
+
+        // add the must list
+        if ( objectClass.getMustAttributeTypeOids() != null && objectClass.getMustAttributeTypeOids().size() != 0 )
+        {
+            Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_MUST_AT ) );
+
+            for ( String mustOid :objectClass.getMustAttributeTypeOids() )
+            {
+                attr.add( mustOid );
+            }
+            
+            entry.put( attr );
+        }
+        
+        // add the may list
+        if ( objectClass.getMayAttributeTypeOids() != null && objectClass.getMayAttributeTypeOids().size() != 0 )
+        {
+            Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_MAY_AT ) );
+
+            for ( String mayOid :objectClass.getMayAttributeTypeOids() )
+            {
+                attr.add( mayOid );
+            }
+            
+            entry.put( attr );
+        }
+        
+        return entry;
+    }
+    
+    
+    private final void injectCommon( SchemaObject object, Entry entry, SchemaManager schemaManager ) throws LdapException
+    {
+        injectNames( object.getNames(), entry, schemaManager );
+        entry.put( MetaSchemaConstants.M_OBSOLETE_AT, getBoolean( object.isObsolete() ) );
+        entry.put( MetaSchemaConstants.M_OID_AT, object.getOid() );
+        
+        if ( object.getDescription() != null )
+        {
+            entry.put( MetaSchemaConstants.M_DESCRIPTION_AT, object.getDescription() );
+        }
+    }
+    
+    
+    private final void injectNames( List<String> names, Entry entry, SchemaManager schemaManager ) throws LdapException
+    {
+        if ( ( names == null ) || ( names.size() == 0 ) )
+        {
+            return;
+        }
+        
+        Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_NAME_AT ) );
+
+        for ( String name:names )
+        {
+            attr.add( name );
+        }
+        
+        entry.put( attr );
+    }
+
+    
+    private final String getBoolean( boolean value )
+    {
+        if ( value ) 
+        {
+            return "TRUE";
+        }
+        else
+        {
+            return "FALSE";
+        }
+    }
+}