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 [2/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/collective/pom.xml
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/collective/pom.xml?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/collective/pom.xml (added)
+++ directory/apacheds/trunk/interceptors/collective/pom.xml Fri Oct 14 22:36:08 2011
@@ -0,0 +1,178 @@
+<?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-collective</artifactId>
+  <name>ApacheDS Collective Attribute Interceptor</name>
+  <packaging>jar</packaging>
+
+  <description>
+    Collective Attribute 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>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/collective/src/main/java/org/apache/directory/server/core/collective/CollectiveAttributeInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/collective/src/main/java/org/apache/directory/server/core/collective/CollectiveAttributeInterceptor.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/collective/src/main/java/org/apache/directory/server/core/collective/CollectiveAttributeInterceptor.java (added)
+++ directory/apacheds/trunk/interceptors/collective/src/main/java/org/apache/directory/server/core/collective/CollectiveAttributeInterceptor.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,501 @@
+/*
+ *  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.collective;
+
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+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.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.OperationContext;
+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.core.api.partition.ByPassConstants;
+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.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.LdapInvalidAttributeTypeException;
+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.Dn;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.SchemaUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An interceptor based service dealing with collective attribute
+ * management.  This service intercepts read operations on entries to
+ * inject collective attribute value pairs into the response based on
+ * the entires inclusion within collectiveAttributeSpecificAreas and
+ * collectiveAttributeInnerAreas.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CollectiveAttributeInterceptor extends BaseInterceptor
+{
+    /** The LoggerFactory used by this Interceptor */
+    private static Logger LOG = LoggerFactory.getLogger( CollectiveAttributeInterceptor.class );
+
+    /**
+     * the search result filter to use for collective attribute injection
+     */
+    private class CollectiveAttributeFilter implements EntryFilter
+    {
+        public boolean accept( SearchingOperationContext operation, Entry entry ) throws Exception
+        {
+            String[] retAttrs = operation.getSearchControls().getReturningAttributes();
+            addCollectiveAttributes( operation, entry, retAttrs );
+            
+            return true;
+        }
+    }
+    
+    /** The CollectiveAttribute search filter */
+    private final EntryFilter SEARCH_FILTER = new CollectiveAttributeFilter();
+
+    
+    //-------------------------------------------------------------------------------------
+    // Initialization
+    //-------------------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public void init( DirectoryService directoryService ) throws LdapException
+    {
+        super.init( directoryService );
+        
+        LOG.debug( "CollectiveAttribute interceptor initilaized" );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Interceptor Method Overrides
+    // ------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public void add( NextInterceptor next, AddOperationContext addContext ) throws LdapException
+    {
+        checkAdd( addContext.getDn(), addContext.getEntry() );
+
+        next.add( addContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor list( NextInterceptor nextInterceptor, ListOperationContext listContext )
+        throws LdapException
+    {
+        EntryFilteringCursor cursor = nextInterceptor.list( listContext );
+        
+        cursor.addEntryFilter( SEARCH_FILTER );
+        
+        return cursor;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( NextInterceptor nextInterceptor, LookupOperationContext lookupContext ) throws LdapException
+    {
+        Entry result = nextInterceptor.lookup( lookupContext );
+
+        // Adding the collective attributes if any
+        if ( ( lookupContext.getAttrsId() == null ) || ( lookupContext.getAttrsId().size() == 0 ) )
+        {
+            addCollectiveAttributes( lookupContext, result, SchemaConstants.ALL_USER_ATTRIBUTES_ARRAY );
+        }
+        else
+        {
+            addCollectiveAttributes( lookupContext, result, lookupContext.getAttrsIdArray() );
+        }
+
+        return result;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( NextInterceptor next, ModifyOperationContext modifyContext ) throws LdapException
+    {
+        checkModify( modifyContext );
+
+        next.modify( modifyContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor search( NextInterceptor nextInterceptor, SearchOperationContext searchContext )
+        throws LdapException
+    {
+        EntryFilteringCursor cursor = nextInterceptor.search( searchContext );
+        
+        cursor.addEntryFilter( SEARCH_FILTER );
+
+        return cursor;
+    }
+
+
+    //-------------------------------------------------------------------------------------
+    // Helper methods
+    //-------------------------------------------------------------------------------------
+    /**
+     * Check if we can add an entry. There are two cases : <br>
+     * <ul>
+     * <li>The entry is a normal entry : it should not contain any 'c-XXX' attributeType</li>
+     * <li>The entry is a collectiveAttributeSubentry
+     * </ul>
+     */
+    private void checkAdd( Dn normName, Entry entry ) throws LdapException
+    {
+        if ( entry.hasObjectClass( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRY_OC ) )
+        {
+            // This is a collectiveAttribute subentry. It must have at least one collective
+            // attribute
+            for ( Attribute attribute : entry )
+            {
+                if ( attribute.getAttributeType().isCollective() )
+                {
+                    return;
+                }
+            }
+            
+            LOG.info( "A CollectiveAttribute subentry *should* have at least one collectiveAttribute" );
+            throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, I18n.err( I18n.ERR_257_COLLECTIVE_SUBENTRY_WITHOUT_COLLECTIVE_AT ) );
+        }
+
+        if ( containsAnyCollectiveAttributes( entry ) )
+        {
+            /*
+             * TODO: Replace the Exception and the ResultCodeEnum with the correct ones.
+             */
+            LOG.info( "Cannot add the entry {} : it contains some CollectiveAttributes and is not a collective subentry",
+                entry );
+            throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, I18n.err( I18n.ERR_241_CANNOT_STORE_COLLECTIVE_ATT_IN_ENTRY ) );
+        }
+    }
+
+    
+    /**
+     * Check that we can modify an entry
+     */
+    private void checkModify( ModifyOperationContext modifyContext ) throws LdapException
+    {
+        List<Modification> mods = modifyContext.getModItems();
+        Entry originalEntry = modifyContext.getEntry();
+        Entry targetEntry = ( Entry ) SchemaUtils.getTargetEntry( mods, originalEntry );
+
+        // If the modified entry contains the CollectiveAttributeSubentry, then the modification
+        // is accepted, no matter what
+        if ( targetEntry.contains( OBJECT_CLASS_AT, SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRY_OC ) )
+        {
+            return;
+        }
+
+        // Check that we don't add any collectve attribute, this is not allowed on normal entries
+        if ( hasCollectiveAttributes( mods ) )
+        {
+            /*
+             * TODO: Replace the Exception and the ResultCodeEnum with the correct ones.
+             */
+            LOG.info( "Cannot modify the entry {} : it contains some CollectiveAttributes and is not a collective subentry",
+                targetEntry );
+            throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, I18n.err( I18n.ERR_242 ) );
+        }
+    }
+
+    
+    /**
+     * Check that we have a CollectiveAttribute in the modifications. (CollectiveAttributes
+     * are those with a name starting with 'c-').
+     */
+    private boolean hasCollectiveAttributes( List<Modification> mods ) throws LdapException
+    {
+        for ( Modification mod : mods )
+        {
+            // TODO: handle http://issues.apache.org/jira/browse/DIRSERVER-1198
+            Attribute attr = mod.getAttribute();
+            AttributeType attrType = attr.getAttributeType();
+
+            // Defensive programming. Very unlikely to happen here...
+            if ( attrType == null )
+            {
+                try
+                {
+                    attrType = schemaManager.lookupAttributeTypeRegistry( attr.getUpId() );
+                }
+                catch ( LdapException le )
+                {
+                    throw new LdapInvalidAttributeTypeException();
+                }
+            }
+
+            ModificationOperation modOp = mod.getOperation();
+
+            // If the AT is collective and we don't try to remove it, then we can return.
+            if ( attrType.isCollective() && ( modOp != ModificationOperation.REMOVE_ATTRIBUTE ) )
+            {
+                return true;
+            }
+        }
+
+        // No collective attrbute found
+        return false;
+    }
+
+    
+    /**
+     * Check if the entry contains any collective AttributeType (those starting with 'c-')
+     */
+    private boolean containsAnyCollectiveAttributes( Entry entry ) throws LdapException
+    {
+        for ( Attribute attribute : entry.getAttributes() )
+        {
+            AttributeType attributeType = attribute.getAttributeType();
+
+            if ( attributeType.isCollective() )
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    
+    /**
+     * Adds the set of collective attributes requested in the returning attribute list
+     * and contained in subentries referenced by the entry. Excludes collective
+     * attributes that are specified to be excluded via the 'collectiveExclusions'
+     * attribute in the entry.
+     *
+     * @param opContext the context of the operation collective attributes 
+     * are added to
+     * @param entry the entry to have the collective attributes injected
+     * @param retAttrs array or attribute type to be specifically included in the result entry(s)
+     * @throws LdapException if there are problems accessing subentries
+     */
+    private void addCollectiveAttributes( OperationContext opContext, Entry entry, String[] retAttrs ) throws LdapException
+    {
+        Attribute collectiveAttributeSubentries = ( ( ClonedServerEntry ) entry ).getOriginalEntry().get(
+            COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT );
+
+        /*
+         * If there are no collective attribute subentries referenced then we 
+         * have no collective attributes to inject to this entry.
+         */
+        if ( collectiveAttributeSubentries == null )
+        {
+            return;
+        }
+
+        /*
+         * Before we proceed we need to lookup the exclusions within the entry 
+         * and build a set of exclusions for rapid lookup.  We use OID values 
+         * in the exclusions set instead of regular names that may have case 
+         * variance.
+         */
+        Attribute collectiveExclusions = ( ( ClonedServerEntry ) entry ).getOriginalEntry().get(
+            COLLECTIVE_EXCLUSIONS_AT );
+        Set<String> exclusions = new HashSet<String>();
+
+        if ( collectiveExclusions != null )
+        {
+            if ( collectiveExclusions.contains( SchemaConstants.EXCLUDE_ALL_COLLECTIVE_ATTRIBUTES_AT_OID )
+                || collectiveExclusions.contains( SchemaConstants.EXCLUDE_ALL_COLLECTIVE_ATTRIBUTES_AT ) )
+            {
+                /*
+                 * This entry does not allow any collective attributes
+                 * to be injected into itself.
+                 */
+                return;
+            }
+
+            exclusions = new HashSet<String>();
+
+            for ( Value<?> value : collectiveExclusions )
+            {
+                AttributeType attrType = schemaManager.lookupAttributeTypeRegistry( value.getString() );
+                exclusions.add( attrType.getOid() );
+            }
+        }
+
+        /*
+         * If no attributes are requested specifically
+         * then it means all user attributes are requested.
+         * So populate the array with all user attributes indicator: "*".
+         */
+        if ( retAttrs == null )
+        {
+            retAttrs = SchemaConstants.ALL_USER_ATTRIBUTES_ARRAY;
+        }
+
+        /*
+         * Construct a set of requested attributes for easier tracking.
+         */
+        Set<String> retIdsSet = new HashSet<String>( retAttrs.length );
+
+        for ( String retAttr : retAttrs )
+        {
+            if ( retAttr.equals( SchemaConstants.ALL_USER_ATTRIBUTES )
+                || retAttr.equals( SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES ) )
+            {
+                retIdsSet.add( retAttr );
+            }
+            else
+            {
+                retIdsSet.add( schemaManager.lookupAttributeTypeRegistry( retAttr ).getOid() );
+            }
+        }
+
+        /*
+         * For each collective subentry referenced by the entry we lookup the
+         * attributes of the subentry and copy collective attributes from the
+         * subentry into the entry.
+         */
+        for ( Value<?> value : collectiveAttributeSubentries )
+        {
+            String subentryDnStr = value.getString();
+            Dn subentryDn = opContext.getSession().getDirectoryService().getDnFactory().create( subentryDnStr );
+
+            /*
+             * TODO - Instead of hitting disk here can't we leverage the 
+             * SubentryService to get us cached sub-entries so we're not
+             * wasting time with a lookup here? It is ridiculous to waste
+             * time looking up this sub-entry. 
+             */
+
+            Entry subentry = opContext.lookup( subentryDn, ByPassConstants.LOOKUP_COLLECTIVE_BYPASS, SchemaConstants.ALL_ATTRIBUTES_ARRAY );
+
+            for ( Attribute attribute : subentry.getAttributes() )
+            {
+                AttributeType attributeType = attribute.getAttributeType();
+                String attrId = attributeType.getName();
+
+                if ( !attributeType.isCollective() )
+                {
+                    continue;
+                }
+
+                /*
+                 * Skip the addition of this collective attribute if it is excluded
+                 * in the 'collectiveAttributes' attribute.
+                 */
+                if ( exclusions.contains( attributeType.getOid() ) )
+                {
+                    continue;
+                }
+
+                Set<AttributeType> allSuperTypes = getAllSuperTypes( attributeType );
+
+                for ( String retId : retIdsSet )
+                {
+                    if ( retId.equals( SchemaConstants.ALL_USER_ATTRIBUTES )
+                        || retId.equals( SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES ) )
+                    {
+                        continue;
+                    }
+
+                    AttributeType retType = schemaManager.lookupAttributeTypeRegistry( retId );
+
+                    if ( allSuperTypes.contains( retType ) )
+                    {
+                        retIdsSet.add( schemaManager.lookupAttributeTypeRegistry( attrId ).getOid() );
+                        break;
+                    }
+                }
+
+                /*
+                 * If not all attributes or this collective attribute requested specifically
+                 * then bypass the inclusion process.
+                 */
+                if ( !( retIdsSet.contains( SchemaConstants.ALL_USER_ATTRIBUTES ) || retIdsSet.contains( schemaManager
+                    .lookupAttributeTypeRegistry( attrId ).getOid() ) ) )
+                {
+                    continue;
+                }
+
+                Attribute subentryColAttr = subentry.get( attrId );
+                Attribute entryColAttr = entry.get( attrId );
+
+                /*
+                 * If entry does not have attribute for collective attribute then create it.
+                 */
+                if ( entryColAttr == null )
+                {
+                    entryColAttr = new DefaultAttribute( schemaManager.lookupAttributeTypeRegistry( attrId ) );
+                    entry.put( entryColAttr );
+                }
+
+                /*
+                 *  Add all the collective attribute values in the subentry
+                 *  to the currently processed collective attribute in the entry.
+                 */
+                for ( Value<?> subentryColVal : subentryColAttr )
+                {
+                    entryColAttr.add( subentryColVal.getString() );
+                }
+            }
+        }
+    }
+
+
+    private Set<AttributeType> getAllSuperTypes( AttributeType id ) throws LdapException
+    {
+        Set<AttributeType> allSuperTypes = new HashSet<AttributeType>();
+        AttributeType superType = id;
+
+        while ( superType != null )
+        {
+            superType = superType.getSuperior();
+
+            if ( superType != null )
+            {
+                allSuperTypes.add( superType );
+            }
+        }
+
+        return allSuperTypes;
+    }
+}

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

Added: directory/apacheds/trunk/interceptors/event/pom.xml
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/event/pom.xml?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/event/pom.xml (added)
+++ directory/apacheds/trunk/interceptors/event/pom.xml Fri Oct 14 22:36:08 2011
@@ -0,0 +1,188 @@
+<?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-event</artifactId>
+  <name>ApacheDS Event Interceptor</name>
+  <packaging>jar</packaging>
+
+  <description>
+    Event 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-interceptors-normalization</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/event/src/main/java/org/apache/directory/server/core/event/DefaultEventService.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/DefaultEventService.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/DefaultEventService.java (added)
+++ directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/DefaultEventService.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,102 @@
+/*
+ *  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.event;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.event.DirectoryListener;
+import org.apache.directory.server.core.api.event.EventService;
+import org.apache.directory.server.core.api.event.NotificationCriteria;
+import org.apache.directory.server.core.api.event.RegistrationEntry;
+import org.apache.directory.server.core.normalization.FilterNormalizingVisitor;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+import org.apache.directory.shared.ldap.model.schema.normalizers.ConcreteNameComponentNormalizer;
+import org.apache.directory.shared.ldap.model.schema.normalizers.NameComponentNormalizer;
+
+/**
+ * A class implementing the EventService interface. It stores all the Listener 
+ * associated with a DirectoryService.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+class DefaultEventService implements EventService
+{
+    /** The list of RegistrationEntries being registered */
+    private List<RegistrationEntry> registrations = new CopyOnWriteArrayList<RegistrationEntry>();
+    
+    /** The DirectoryService instance */
+    private DirectoryService directoryService;
+    
+    /** A normalizer used for filters */
+    private FilterNormalizingVisitor filterNormalizer;
+
+    /**
+     * Create an instance of EventService
+     * @param directoryService The associated DirectoryService
+     * @param registrations The list of Registrations
+     */
+    public DefaultEventService( DirectoryService directoryService )
+    {
+        this.directoryService= directoryService;
+        SchemaManager schemaManager = directoryService.getSchemaManager();
+        NameComponentNormalizer ncn = new ConcreteNameComponentNormalizer( schemaManager );
+        filterNormalizer = new FilterNormalizingVisitor( ncn, schemaManager );
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void addListener( DirectoryListener listener, NotificationCriteria criteria ) throws Exception
+    {
+        criteria.getBase().apply( directoryService.getSchemaManager() );
+        ExprNode result = ( ExprNode ) criteria.getFilter().accept( filterNormalizer );
+        criteria.setFilter( result );
+        registrations.add( new RegistrationEntry( listener, criteria ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removeListener( DirectoryListener listener )
+    {
+        for ( RegistrationEntry entry : registrations )
+        {
+            if ( entry.getListener() == listener )
+            {
+                registrations.remove( entry );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public List<RegistrationEntry> getRegistrationEntries()
+    {
+        return Collections.unmodifiableList( registrations );
+    }
+}

Added: directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/EventInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/EventInterceptor.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/EventInterceptor.java (added)
+++ directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/EventInterceptor.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,346 @@
+/*
+ *  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.event;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.entry.ClonedServerEntry;
+import org.apache.directory.server.core.api.event.DirectoryListener;
+import org.apache.directory.server.core.api.event.Evaluator;
+import org.apache.directory.server.core.api.event.EventType;
+import org.apache.directory.server.core.api.event.NotificationCriteria;
+import org.apache.directory.server.core.api.event.RegistrationEntry;
+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.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.OperationContext;
+import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
+import org.apache.directory.server.core.api.partition.ByPassConstants;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+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.name.Dn;
+import org.apache.directory.shared.ldap.model.schema.normalizers.ConcreteNameComponentNormalizer;
+import org.apache.directory.shared.ldap.model.schema.normalizers.NameComponentNormalizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An {@link org.apache.directory.server.core.api.interceptor.Interceptor} based service for notifying {@link
+ * DirectoryListener}s of changes to the DIT.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EventInterceptor extends BaseInterceptor
+{
+    /** A logger for this class */
+    private final static Logger LOG = LoggerFactory.getLogger( EventInterceptor.class );
+    
+    private Evaluator evaluator;
+    private ExecutorService executor;
+
+
+    /**
+     * Initialize the event interceptor. It creates a pool of executor which will be used
+     * to call the listeners in separate threads.
+     */
+    public void init( DirectoryService directoryService ) throws LdapException
+    {
+        LOG.info( "Initializing ..." );
+        super.init( directoryService );
+
+        NameComponentNormalizer ncn = new ConcreteNameComponentNormalizer( schemaManager );
+        evaluator = new ExpressionEvaluator( schemaManager );
+        executor = new ThreadPoolExecutor( 1, 10, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>( 100 ) );
+
+        this.directoryService.setEventService( new DefaultEventService( directoryService ) );
+        LOG.info( "Initialization complete." );
+    }
+
+
+    /**
+     * Call the listener passing it the context.
+     */
+    private void fire( final OperationContext opContext, EventType type, final DirectoryListener listener )
+    {
+        switch ( type )
+        {
+            case ADD:
+                executor.execute( new Runnable()
+                {
+                    public void run()
+                    {
+                        listener.entryAdded( ( AddOperationContext ) opContext );
+                    }
+                } );
+                
+                break;
+                
+            case DELETE:
+                executor.execute( new Runnable()
+                {
+                    public void run()
+                    {
+                        listener.entryDeleted( ( DeleteOperationContext ) opContext );
+                    }
+                } );
+                
+                break;
+                
+            case MODIFY:
+                executor.execute( new Runnable()
+                {
+                    public void run()
+                    {
+                        listener.entryModified( ( ModifyOperationContext ) opContext );
+                    }
+                } );
+                
+                break;
+                
+            case MOVE:
+                executor.execute( new Runnable()
+                {
+                    public void run()
+                    {
+                        listener.entryMoved( ( MoveOperationContext ) opContext );
+                    }
+                } );
+                
+                break;
+
+            case RENAME:
+                executor.execute( new Runnable()
+                {
+                    public void run()
+                    {
+                        listener.entryRenamed( ( RenameOperationContext ) opContext );
+                    }
+                } );
+                
+                break;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void add( NextInterceptor next, final AddOperationContext addContext ) throws LdapException
+    {
+        next.add( addContext );
+        
+        List<RegistrationEntry> selecting = getSelectingRegistrations( addContext.getDn(), addContext.getEntry() );
+
+        if ( selecting.isEmpty() )
+        {
+            return;
+        }
+
+        for ( final RegistrationEntry registration : selecting )
+        {
+            if ( EventType.isAdd( registration.getCriteria().getEventMask() ) )
+            {
+                fire( addContext, EventType.ADD, registration.getListener() );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void delete( NextInterceptor next, final DeleteOperationContext deleteContext ) throws LdapException
+    {
+        List<RegistrationEntry> selecting = getSelectingRegistrations( deleteContext.getDn(), deleteContext.getEntry() );
+        next.delete( deleteContext );
+
+        if ( selecting.isEmpty() )
+        {
+            return;
+        }
+
+        for ( final RegistrationEntry registration : selecting )
+        {
+            if ( EventType.isDelete( registration.getCriteria().getEventMask() ) )
+            {
+                fire( deleteContext, EventType.DELETE, registration.getListener() );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( NextInterceptor next, final ModifyOperationContext modifyContext ) throws LdapException
+    {
+        Entry oriEntry = modifyContext.getEntry();
+
+        List<RegistrationEntry> selecting = getSelectingRegistrations( modifyContext.getDn(), oriEntry );
+
+        next.modify( modifyContext );
+
+        if ( selecting.isEmpty() )
+        {
+            return;
+        }
+
+        // Get the modified entry
+        Entry alteredEntry = modifyContext.lookup( modifyContext.getDn(), ByPassConstants.LOOKUP_BYPASS, SchemaConstants.ALL_ATTRIBUTES_ARRAY );
+        modifyContext.setAlteredEntry( alteredEntry );
+
+        for ( final RegistrationEntry registration : selecting )
+        {
+            if ( EventType.isModify( registration.getCriteria().getEventMask() ) )
+            {
+                fire( modifyContext, EventType.MODIFY, registration.getListener() );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws LdapException
+    {
+        Entry oriEntry = ((ClonedServerEntry)renameContext.getEntry()).getOriginalEntry();
+        List<RegistrationEntry> selecting = getSelectingRegistrations( renameContext.getDn(), oriEntry );
+
+        next.rename( renameContext );
+
+        if ( selecting.isEmpty() )
+        {
+            return;
+        }
+
+        // Get the modifed entry
+        Entry alteredEntry = renameContext.lookup( renameContext.getNewDn(), ByPassConstants.LOOKUP_BYPASS, SchemaConstants.ALL_ATTRIBUTES_ARRAY );
+        renameContext.setModifiedEntry( alteredEntry );
+
+        for ( final RegistrationEntry registration : selecting )
+        {
+            if ( EventType.isRename( registration.getCriteria().getEventMask() ) )
+            {
+                fire( renameContext, EventType.RENAME, registration.getListener() );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void moveAndRename( NextInterceptor next, final MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
+    {
+        Entry oriEntry = moveAndRenameContext.getOriginalEntry();
+        List<RegistrationEntry> selecting = getSelectingRegistrations( moveAndRenameContext.getDn(), oriEntry );
+        next.moveAndRename( moveAndRenameContext );
+
+        if ( selecting.isEmpty() )
+        {
+            return;
+        }
+
+        for ( final RegistrationEntry registration : selecting )
+        {
+            if ( EventType.isMoveAndRename( registration.getCriteria().getEventMask() ) )
+            {
+                executor.execute( new Runnable()
+                {
+                    public void run()
+                    {
+                        registration.getListener().entryMovedAndRenamed( moveAndRenameContext );
+                    }
+                } );
+            }
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void move( NextInterceptor next, MoveOperationContext moveContext ) throws LdapException
+    {
+        Entry oriEntry = moveContext.getOriginalEntry();
+        List<RegistrationEntry> selecting = getSelectingRegistrations( moveContext.getDn(), oriEntry );
+
+        next.move( moveContext );
+
+        if ( selecting.isEmpty() )
+        {
+            return;
+        }
+
+        for ( final RegistrationEntry registration : selecting )
+        {
+            if ( EventType.isMove( registration.getCriteria().getEventMask() ) )
+            {
+                fire( moveContext, EventType.MOVE, registration.getListener() );
+            }
+        }
+    }
+
+
+    /**
+     * Find a list of registrationEntries given an entry and a name. We check against
+     * the criteria for each registrationEntry
+     */
+    private List<RegistrationEntry> getSelectingRegistrations( Dn name, Entry entry ) throws LdapException
+    {
+        if ( directoryService.getEventService().getRegistrationEntries().isEmpty() )
+        {
+            return Collections.emptyList();
+        }
+
+        List<RegistrationEntry> selecting = new ArrayList<RegistrationEntry>();
+
+        for ( RegistrationEntry registration : directoryService.getEventService().getRegistrationEntries() )
+        {
+            NotificationCriteria criteria = registration.getCriteria();
+
+            Dn base = criteria.getBase();
+
+            // fix for DIRSERVER-1502
+            if ( ( name.equals( base ) || name.isDescendantOf( base ) )
+                && evaluator.evaluate( criteria.getFilter(), base, entry ) )
+            {
+                selecting.add( registration );
+            }
+        }
+
+        return selecting;
+    }
+}

Added: directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/ExpressionEvaluator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/ExpressionEvaluator.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/ExpressionEvaluator.java (added)
+++ directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/ExpressionEvaluator.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,145 @@
+/*
+ *  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.event;
+
+
+import org.apache.directory.server.core.api.event.Evaluator;
+import org.apache.directory.server.i18n.I18n;
+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.exception.LdapInvalidSearchFilterException;
+import org.apache.directory.shared.ldap.model.filter.AndNode;
+import org.apache.directory.shared.ldap.model.filter.BranchNode;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.NotNode;
+import org.apache.directory.shared.ldap.model.filter.OrNode;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+
+
+
+/**
+ * Top level filter expression evaluator implementation.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExpressionEvaluator implements Evaluator
+{
+    /** Leaf Evaluator flyweight use for leaf filter assertions */
+    private LeafEvaluator leafEvaluator;
+
+
+    // ------------------------------------------------------------------------
+    // C O N S T R U C T O R S
+    // ------------------------------------------------------------------------
+    /**
+     * Creates a top level Evaluator where leaves are delegated to a leaf node
+     * evaluator which is already provided.
+     *
+     * @param leafEvaluator handles leaf node evaluation.
+     */
+    public ExpressionEvaluator( LeafEvaluator leafEvaluator )
+    {
+        this.leafEvaluator = leafEvaluator;
+    }
+
+
+    /**
+     * Creates a top level Evaluator where leaves are delegated to a leaf node
+     * evaluator which will be created.
+     *
+     * @param schemaManager The server schemaManager
+     */
+    public ExpressionEvaluator( SchemaManager schemaManager )
+    {
+        SubstringEvaluator substringEvaluator = null;
+        substringEvaluator = new SubstringEvaluator();
+//      leafEvaluator = new LeafEvaluator( schemaManager, substringEvaluator );
+        leafEvaluator = new LeafEvaluator( substringEvaluator );
+    }
+
+
+    /**
+     * Gets the leaf evaluator used by this top level expression evaluator.
+     *
+     * @return the leaf evaluator used by this top level expression evaluator
+     */
+    public LeafEvaluator getLeafEvaluator()
+    {
+        return leafEvaluator;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Evaluator.evaluate() implementation
+    // ------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public boolean evaluate( ExprNode node, Dn dn, Entry entry ) throws LdapException
+    {
+        if ( node.isLeaf() )
+        {
+            return leafEvaluator.evaluate( node, dn, entry );
+        }
+
+        BranchNode bnode = ( BranchNode ) node;
+
+        if ( bnode instanceof OrNode )
+        {
+            for ( ExprNode child: bnode.getChildren() )
+            {
+                if ( evaluate( child, dn, entry ) )
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+        else if ( bnode instanceof AndNode)
+        {
+            for ( ExprNode child: bnode.getChildren() )
+            {
+                boolean res = evaluate( child, dn, entry );
+                
+                if ( !res )
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+        else if ( bnode instanceof NotNode)
+        {
+            if ( null != bnode.getFirstChild() )
+            {
+                return !evaluate( bnode.getFirstChild(), dn, entry );
+            }
+
+            throw new LdapInvalidSearchFilterException( I18n.err( I18n.ERR_243, node ) );
+        }
+        else
+        {
+                throw new LdapInvalidSearchFilterException( I18n.err( I18n.ERR_244, bnode ) );
+        }
+    }
+}

Added: directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/LeafEvaluator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/LeafEvaluator.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/LeafEvaluator.java (added)
+++ directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/LeafEvaluator.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,392 @@
+/*
+ *  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.event;
+
+
+import java.util.Comparator;
+
+import org.apache.directory.server.core.api.event.Evaluator;
+import org.apache.directory.server.i18n.I18n;
+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.Value;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidSearchFilterException;
+import org.apache.directory.shared.ldap.model.filter.ApproximateNode;
+import org.apache.directory.shared.ldap.model.filter.EqualityNode;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.shared.ldap.model.filter.GreaterEqNode;
+import org.apache.directory.shared.ldap.model.filter.LessEqNode;
+import org.apache.directory.shared.ldap.model.filter.PresenceNode;
+import org.apache.directory.shared.ldap.model.filter.ScopeNode;
+import org.apache.directory.shared.ldap.model.filter.SimpleNode;
+import org.apache.directory.shared.ldap.model.filter.SubstringNode;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.LdapComparator;
+import org.apache.directory.shared.ldap.model.schema.MatchingRule;
+import org.apache.directory.shared.ldap.model.schema.Normalizer;
+import org.apache.directory.shared.util.exception.NotImplementedException;
+
+
+/**
+ * Evaluates LeafNode assertions on candidates using a database.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LeafEvaluator implements Evaluator
+{
+    /** equality matching type constant */
+    private static final int EQUALITY_MATCH = 0;
+    
+    /** ordering matching type constant */
+    private static final int ORDERING_MATCH = 1;
+    
+    /** substring matching type constant */
+    private static final int SUBSTRING_MATCH = 3;
+
+//    /** SchemaManager needed for normalizing and comparing values */
+//    private SchemaManager schemaManager;
+    
+    /** Substring node evaluator we depend on */
+    private SubstringEvaluator substringEvaluator;
+    
+    /** ScopeNode evaluator we depend on */
+    private ScopeEvaluator scopeEvaluator;
+
+    /** Constants used for comparisons */
+    private static final boolean COMPARE_GREATER = true;
+    private static final boolean COMPARE_LESSER = false;
+
+
+    /**
+     * Creates a leaf expression node evaluator.
+     *
+     * @param schemaManager The server schemaManager
+     */
+    public LeafEvaluator( SubstringEvaluator substringEvaluator )
+    {
+        this.scopeEvaluator = new ScopeEvaluator();
+        this.substringEvaluator = substringEvaluator;
+    }
+
+
+//    /**
+//     * Creates a leaf expression node evaluator.
+//     *
+//     * @param schemaManager The server schemaManager
+//     */
+//    public LeafEvaluator( SchemaManager schemaManager,
+//        SubstringEvaluator substringEvaluator )
+//    {
+//        this.schemaManager = schemaManager;
+//        this.scopeEvaluator = new ScopeEvaluator();
+//        this.substringEvaluator = substringEvaluator;
+//    }
+
+
+    public ScopeEvaluator getScopeEvaluator()
+    {
+        return scopeEvaluator;
+    }
+
+
+    public SubstringEvaluator getSubstringEvaluator()
+    {
+        return substringEvaluator;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean evaluate( ExprNode node, Dn dn, Entry entry ) throws LdapException
+    {
+        if ( node instanceof ScopeNode )
+        {
+            return scopeEvaluator.evaluate( node, dn, entry );
+        }
+
+        if ( node instanceof PresenceNode )
+        {
+            return evalPresence( ( ( PresenceNode ) node ).getAttributeType(), entry );
+        }
+        else if ( ( node instanceof EqualityNode ) || ( node instanceof ApproximateNode ) )
+        {
+            return evalEquality( ( EqualityNode<?> ) node, entry );
+        }
+        else if ( node instanceof GreaterEqNode )
+        {
+            return evalGreaterOrLesser( ( GreaterEqNode<?> ) node, entry, COMPARE_GREATER );
+        }
+        else if ( node instanceof LessEqNode)
+        {
+            return evalGreaterOrLesser( ( LessEqNode<?> ) node, entry, COMPARE_LESSER );
+        }
+        else if ( node instanceof SubstringNode )
+        {
+            return substringEvaluator.evaluate( node, dn, entry );
+        }
+        else if ( node instanceof ExtensibleNode )
+        {
+            throw new NotImplementedException();
+        }
+        else
+        {
+            throw new LdapInvalidSearchFilterException( I18n.err( I18n.ERR_245, node ) );
+        }
+    }
+
+
+    /**
+     * Evaluates a simple greater than or less than attribute value assertion on
+     * a perspective candidate.
+     * 
+     * @param node the greater than or less than node to evaluate
+     * @param entry the perspective candidate
+     * @param isGreater true if it is a greater than or equal to comparison,
+     *      false if it is a less than or equal to comparison.
+     * @return the ava evaluation on the perspective candidate
+     * @throws LdapException if there is a database access failure
+     */
+    @SuppressWarnings("unchecked")
+    private boolean evalGreaterOrLesser( SimpleNode<?> node, Entry entry, boolean isGreaterOrLesser )
+        throws LdapException
+    {
+        AttributeType attributeType = node.getAttributeType();
+
+        // get the attribute associated with the node
+        Attribute attr = entry.get( node.getAttribute() );
+
+        // If we do not have the attribute just return false
+        if ( null == attr )
+        {
+            return false;
+        }
+
+        /*
+         * We need to iterate through all values and for each value we normalize
+         * and use the comparator to determine if a match exists.
+         */
+        Normalizer normalizer = getNormalizer( attributeType );
+        Comparator comparator = getComparator( attributeType );
+        Object filterValue = normalizer.normalize( node.getValue() );
+
+        /*
+         * Cheaper to not check isGreater in one loop - better to separate
+         * out into two loops which you choose to execute based on isGreater
+         */
+        if ( isGreaterOrLesser == COMPARE_GREATER )
+        {
+            for ( Value<?> value : attr )
+            {
+                Object normValue = normalizer.normalize( value );
+
+                // Found a value that is greater than or equal to the ava value
+                if ( comparator.compare( normValue, filterValue ) >= 0 )
+                {
+                    return true;
+                }
+            }
+        }
+        else
+        {
+            for ( Value<?> value : attr )
+            {
+                Object normValue = normalizer.normalize( value );
+
+                // Found a value that is less than or equal to the ava value
+                if ( comparator.compare( normValue, filterValue ) <= 0 )
+                {
+                    return true;
+                }
+            }
+        }
+
+        // no match so return false
+        return false;
+    }
+
+
+    /**
+     * Evaluates a simple presence attribute value assertion on a perspective
+     * candidate.
+     * 
+     * @param attrId the name of the attribute tested for presence 
+     * @param entry the perspective candidate
+     * @return the ava evaluation on the perspective candidate
+     */
+    private boolean evalPresence( AttributeType attributeType, Entry entry ) throws LdapException
+    {
+        if ( entry == null )
+        {
+            return false;
+        }
+
+        return null != entry.get( attributeType );
+    }
+
+
+    /**
+     * Evaluates a simple equality attribute value assertion on a perspective
+     * candidate.
+     *
+     * @param node the equality node to evaluate
+     * @param entry the perspective candidate
+     * @return the ava evaluation on the perspective candidate
+     * @throws org.apache.directory.shared.ldap.model.exception.LdapException if there is a database access failure
+     */
+    @SuppressWarnings("unchecked")
+    private boolean evalEquality( EqualityNode<?> node, Entry entry ) throws LdapException
+    {
+        Normalizer normalizer = getNormalizer( node.getAttributeType() );
+        Comparator comparator = getComparator( node.getAttributeType() );
+
+        // get the attribute associated with the node
+        Attribute attr = entry.get( node.getAttribute() );
+
+        // If we do not have the attribute just return false
+        if ( null == attr )
+        {
+            return false;
+        }
+
+        // check if Ava value exists in attribute
+        AttributeType attributeType = node.getAttributeType();
+        Value<?> value = null;
+        
+        if ( attributeType.getSyntax().isHumanReadable() )
+        {
+            if ( node.getValue().isHumanReadable() )
+            {
+                value = node.getValue();
+            }
+            else
+            {
+                value = new org.apache.directory.shared.ldap.model.entry.StringValue( node.getValue().getString() );
+            }
+        }
+        else
+        {
+            value = node.getValue();
+        }
+        
+        if ( attr.contains( value ) )
+        {
+            return true;
+        }
+
+        // get the normalized Ava filter value
+        Value<?> filterValue = normalizer.normalize( value );
+
+        // check if the normalized value is present
+        if ( attr.contains( filterValue ) )
+        {
+            return true;
+        }
+
+        /*
+         * We need to now iterate through all values because we could not get
+         * a lookup to work.  For each value we normalize and use the comparator
+         * to determine if a match exists.
+         */
+        for ( Value<?> val : attr )
+        {
+            Value<?> normValue = normalizer.normalize( val );
+
+            if ( 0 == comparator.compare( normValue.getValue(), filterValue.getValue() ) )
+            {
+                return true;
+            }
+        }
+
+        // no match so return false
+        return false;
+    }
+
+
+    /**
+     * Gets the comparator for equality matching.
+     *
+     * @param attributeType the attributeType
+     * @return the comparator for equality matching
+     * @throws LdapException if there is a failure
+     */
+    private LdapComparator<? super Object> getComparator( AttributeType attributeType ) throws LdapException
+    {
+        MatchingRule mrule = getMatchingRule( attributeType, EQUALITY_MATCH );
+        
+        return mrule.getLdapComparator();
+    }
+
+
+    /**
+     * Gets the normalizer for equality matching.
+     *
+     * @param attributeType the attributeType
+     * @return the normalizer for equality matching
+     * @throws LdapException if there is a failure
+     */
+    private Normalizer getNormalizer( AttributeType attributeType ) throws LdapException
+    {
+        MatchingRule mrule = getMatchingRule( attributeType, EQUALITY_MATCH );
+        
+        return mrule.getNormalizer();
+    }
+
+
+    /**
+     * Gets the matching rule for an attributeType.
+     *
+     * @param attributeType the attributeType
+     * @return the matching rule
+     * @throws LdapException if there is a failure
+     */
+    private MatchingRule getMatchingRule( AttributeType attributeType, int matchType ) throws LdapException
+    {
+        MatchingRule mrule = null;
+
+        switch ( matchType )
+        {
+            case ( EQUALITY_MATCH ):
+                mrule = attributeType.getEquality();
+                break;
+
+            case ( SUBSTRING_MATCH ):
+                mrule = attributeType.getSubstring();
+                break;
+
+            case ( ORDERING_MATCH ):
+                mrule = attributeType.getOrdering();
+                break;
+
+            default:
+                throw new LdapException( I18n.err( I18n.ERR_246, matchType ) );
+        }
+
+        if ( ( mrule == null ) && ( matchType != EQUALITY_MATCH ) )
+        {
+            mrule = attributeType.getEquality();
+        }
+
+        return mrule;
+    }
+}

Added: directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/ScopeEvaluator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/ScopeEvaluator.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/ScopeEvaluator.java (added)
+++ directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/ScopeEvaluator.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,70 @@
+/*
+ *  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.event;
+
+
+import org.apache.directory.server.core.api.event.Evaluator;
+import org.apache.directory.server.i18n.I18n;
+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.exception.LdapInvalidSearchFilterException;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.ScopeNode;
+import org.apache.directory.shared.ldap.model.name.Dn;
+
+
+/**
+ * Evaluates ScopeNode assertions on candidates.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ScopeEvaluator implements Evaluator
+{
+    public ScopeEvaluator()
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean evaluate( ExprNode node, Dn dn, Entry record ) throws LdapException
+    {
+        ScopeNode snode = ( ScopeNode ) node;
+
+        switch ( snode.getScope() )
+        {
+            case OBJECT:
+                return dn.equals( snode.getBaseDn() );
+            
+            case ONELEVEL:
+                if ( dn.isDescendantOf( snode.getBaseDn() ) )
+                {
+                    return ( snode.getBaseDn().size() + 1 ) == dn.size();
+                }
+            
+            case SUBTREE:
+                return dn.isDescendantOf( snode.getBaseDn() );
+            
+            default:
+                throw new LdapInvalidSearchFilterException( I18n.err( I18n.ERR_247 ) );
+        }
+    }
+}

Added: directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/SubstringEvaluator.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/SubstringEvaluator.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/SubstringEvaluator.java (added)
+++ directory/apacheds/trunk/interceptors/event/src/main/java/org/apache/directory/server/core/event/SubstringEvaluator.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,117 @@
+/*
+ *  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.event;
+
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.directory.server.core.api.event.Evaluator;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.Attribute;
+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.LdapInvalidSearchFilterException;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.SubstringNode;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.MatchingRule;
+import org.apache.directory.shared.ldap.model.schema.Normalizer;
+
+
+/**
+ * Evaluates substring filter assertions on an entry.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SubstringEvaluator implements Evaluator
+{
+    /**
+     * Creates a new SubstringEvaluator for substring expressions.
+     */
+    public SubstringEvaluator()
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean evaluate( ExprNode node, Dn dn, Entry entry ) throws LdapException
+    {
+        Pattern regex = null;
+        SubstringNode snode = (SubstringNode)node;
+        AttributeType attributeType = snode.getAttributeType();
+        MatchingRule matchingRule = attributeType.getSubstring();
+        
+        if ( matchingRule == null )
+        {
+            matchingRule = attributeType.getEquality();
+        }
+        
+        Normalizer normalizer = matchingRule.getNormalizer();
+        
+
+        // get the attribute
+        Attribute attr = entry.get( snode.getAttribute() );
+
+        // if the attribute does not exist just return false
+        if ( null == attr )
+        {
+            return false;
+        }
+
+        // compile the regular expression to search for a matching attribute
+        try
+        {
+            regex = snode.getRegex( normalizer );
+        }
+        catch ( PatternSyntaxException pse )
+        {
+            LdapInvalidSearchFilterException ne = new LdapInvalidSearchFilterException( I18n.err( I18n.ERR_248, node ) );
+            ne.initCause( pse );
+            throw ne;
+        }
+
+        /*
+         * Cycle through the attribute values testing normalized version 
+         * obtained from using the substring matching rule's normalizer.
+         * The test uses the comparator obtained from the appropriate 
+         * substring matching rule.
+         */
+
+        for ( Value<?> value: attr )
+        {
+            String normValue = normalizer.normalize( value.getString() );
+
+            // Once match is found cleanup and return true
+
+            if ( regex.matcher( normValue ).matches() )
+            {
+                return true;
+            }
+        }
+
+        // we fell through so a match was not found - assertion was false.
+        return false;
+    }
+}

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

Added: directory/apacheds/trunk/interceptors/exception/pom.xml
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/exception/pom.xml?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/exception/pom.xml (added)
+++ directory/apacheds/trunk/interceptors/exception/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-exception</artifactId>
+  <name>ApacheDS Exception Interceptor</name>
+  <packaging>jar</packaging>
+
+  <description>
+    Exception 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>
+