directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kayyag...@apache.org
Subject svn commit: r917683 - in /directory/apacheds/trunk: core-api/src/main/java/org/apache/directory/server/core/filtering/ core-integ/src/test/java/org/apache/directory/server/core/operations/search/ core/src/main/java/org/apache/directory/server/core/part...
Date Mon, 01 Mar 2010 19:58:06 GMT
Author: kayyagari
Date: Mon Mar  1 19:58:06 2010
New Revision: 917683

URL: http://svn.apache.org/viewvc?rev=917683&view=rev
Log:
o fix for DIRSERVER-1214
o a new cursor implementation to evaluate entries returned from various partitions
o added test cases

Added:
    directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/filtering/CursorList.java
Modified:
    directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/operations/search/SearchIT.java
    directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java

Added: directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/filtering/CursorList.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/filtering/CursorList.java?rev=917683&view=auto
==============================================================================
--- directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/filtering/CursorList.java
(added)
+++ directory/apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/filtering/CursorList.java
Mon Mar  1 19:58:06 2010
@@ -0,0 +1,490 @@
+/*
+ * 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.filtering;
+
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.directory.server.core.entry.ClonedServerEntry;
+import org.apache.directory.server.core.interceptor.context.SearchingOperationContext;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.cursor.ClosureMonitor;
+import org.apache.directory.shared.ldap.cursor.Cursor;
+import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
+import org.apache.directory.shared.ldap.cursor.ListCursor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * An implementation of a Cursor based on a {@link List} of {@link Cursor}s.  Optionally,
the
+ * Cursor may be limited to a specific range within the list.
+ * 
+ * This class is modeled based on the implementation of {@link ListCursor}
+ * 
+ * WARN this is only used internally 
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class CursorList implements EntryFilteringCursor
+{
+    /** The inner List */
+    private final List<EntryFilteringCursor> list;
+
+    /** The starting position for the cursor in the list. It can be > 0 */
+    private final int start;
+
+    /** The ending position for the cursor in the list. It can be < List.size() */
+    private final int end;
+
+    /** The current position in the list */
+    private int index = -1;
+
+    /** the operation context */
+    private SearchingOperationContext opContext;
+
+    /** flag to detect the closed cursor */
+    private boolean closed;
+
+    private static final Logger LOG = LoggerFactory.getLogger( CursorList.class );
+
+
+    /**
+     * Creates a new ListCursor with lower (inclusive) and upper (exclusive)
+     * bounds.
+     *
+     * As with all Cursors, this ListCursor requires a successful return from
+     * advance operations (next() or previous()) to properly return values
+     * using the get() operation.
+     *
+     * @param start the lower bound index
+     * @param list the list this ListCursor operates on
+     * @param end the upper bound index
+     */
+    public CursorList( int start, List<EntryFilteringCursor> list, int end, SearchingOperationContext
opContext )
+    {
+        if ( ( start < 0 ) || ( start > list.size() ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_02005, start ) );
+        }
+
+        if ( ( end < 0 ) || ( end > list.size() ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_02006, end ) );
+        }
+
+        // check list is not empty list since the empty list is the only situation
+        // where we allow for start to equal the end: in other cases it makes no sense
+        if ( ( list.size() > 0 ) && ( start >= end ) )
+        {
+            throw new IllegalArgumentException( I18n.err( I18n.ERR_02007, start, end ) );
+        }
+
+        if ( list != null )
+        {
+            this.list = list;
+        }
+        else
+        {
+            this.list = Collections.emptyList();
+        }
+
+        this.start = start;
+        this.end = end;
+        this.opContext = opContext;
+    }
+
+
+    /**
+     * Creates a new ListCursor without specific bounds: the bounds are
+     * acquired from the size of the list.
+     *
+     * @param list the backing for this ListCursor
+     */
+    public CursorList( List<EntryFilteringCursor> list, SearchingOperationContext opContext
)
+    {
+        this( 0, list, list.size(), opContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean available()
+    {
+        if ( index >= 0 && index < end )
+        {
+            return list.get( index ).available(); 
+        }
+        
+        return false;
+    }
+
+
+    /**
+     * @throws IllegalStateException if the underlying list is not sorted
+     * and/or a comparator is not provided.
+     */
+    public void before( ClonedServerEntry element ) throws Exception
+    {
+        // checkNotClosed( "before()" );
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02008 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void after( ClonedServerEntry element ) throws Exception
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02008 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void beforeFirst() throws Exception
+    {
+        this.index = -1;
+        list.get( index ).beforeFirst();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void afterLast() throws Exception
+    {
+        this.index = end;
+        list.get( index ).afterLast();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean first() throws Exception
+    {
+        if ( list.size() > 0 )
+        {
+            index = start;
+            return list.get( index ).first();
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean last() throws Exception
+    {
+        if ( list.size() > 0 )
+        {
+            index = end - 1;
+            return list.get( index ).last();
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isFirst() throws Exception
+    {
+        return ( list.size() > 0 ) && ( index == start ) && list.get(
index ).first();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isLast() throws Exception
+    {
+        return ( list.size() > 0 ) && ( index == end - 1 ) && list.get(
index ).last();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isAfterLast() throws Exception
+    {
+        return index == end;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isBeforeFirst() throws Exception
+    {
+        return index == -1;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean previous() throws Exception
+    {
+        // if parked at -1 we cannot go backwards
+        if ( index == -1 )
+        {
+            return false;
+        }
+
+        // if the index moved back is still greater than or eq to start then OK
+        if ( index - 1 >= start )
+        {
+            if ( index == end )
+            {
+                index--;
+            }
+
+            if ( !list.get( index ).previous() )
+            {
+                index--;
+                if ( index != -1 )
+                {
+                    return list.get( index ).previous();
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                return true;
+            }
+        }
+
+        // if the index currently less than or equal to start we need to park it at -1 and
return false
+        if ( index <= start )
+        {
+            if ( !list.get( index ).previous() )
+            {
+                index = -1;
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+
+        if ( list.size() <= 0 )
+        {
+            index = -1;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean next() throws Exception
+    {
+        // if parked at -1 we advance to the start index and return true
+        if ( list.size() > 0 && index == -1 )
+        {
+            index = start;
+            return list.get( index ).next();
+        }
+
+        // if the index plus one is less than the end then increment and return true
+        if ( list.size() > 0 && index + 1 < end )
+        {
+            if ( !list.get( index ).next() )
+            {
+                index++;
+                if ( index < end )
+                {
+                    return list.get( index ).next();
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                return true;
+            }
+        }
+
+        // if the index plus one is equal to the end then increment and return false
+        if ( list.size() > 0 && index + 1 == end )
+        {
+            if ( !list.get( index ).next() )
+            {
+                index++;
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+
+        if ( list.size() <= 0 )
+        {
+            index = end;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ClonedServerEntry get() throws Exception
+    {
+        if ( index < start || index >= end )
+        {
+            throw new IOException( I18n.err( I18n.ERR_02009 ) );
+        }
+
+        if( list.get( index ).available() )
+        {
+            return ( ClonedServerEntry ) list.get( index ).get();
+        }
+        throw new InvalidCursorPositionException();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isElementReused()
+    {
+        return true;
+    }
+
+
+    public boolean addEntryFilter( EntryFilter filter )
+    {
+        for( EntryFilteringCursor efc : list )
+        {
+            efc.addEntryFilter( filter );
+        }
+        
+        // returning hard coded value, shouldn't be a problem
+        return true;
+    }
+
+
+    public List<EntryFilter> getEntryFilters()
+    {
+        throw new UnsupportedOperationException( "CursorList doesn't support this operation"
);
+    }
+
+
+    public SearchingOperationContext getOperationContext()
+    {
+        return opContext;
+    }
+
+
+    public boolean isAbandoned()
+    {
+        return getOperationContext().isAbandoned();
+    }
+
+
+    public boolean removeEntryFilter( EntryFilter filter )
+    {
+        return false;
+    }
+
+
+    public void setAbandoned( boolean abandoned )
+    {
+        getOperationContext().setAbandoned( abandoned );
+
+        if ( abandoned )
+        {
+            LOG.info( "Cursor has been abandoned." );
+        }
+    }
+
+
+    public void close() throws Exception
+    {
+        close( null );
+    }
+
+
+    public void close( Exception reason ) throws Exception
+    {
+        closed = true;
+        for ( Cursor c : list )
+        {
+            try
+            {
+                if ( reason != null )
+                {
+                    c.close();
+                }
+                else
+                {
+                    c.close( reason );
+                }
+            }
+            catch ( Exception e )
+            {
+                LOG.warn( "Failed to close the cursor" );
+            }
+        }
+    }
+
+
+    public boolean isClosed() throws Exception
+    {
+        return closed;
+    }
+
+
+    public Iterator<ClonedServerEntry> iterator()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void setClosureMonitor( ClosureMonitor monitor )
+    {
+        for ( Cursor c : list )
+        {
+            c.setClosureMonitor( monitor );
+        }
+    }
+
+}

Modified: directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/operations/search/SearchIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/operations/search/SearchIT.java?rev=917683&r1=917682&r2=917683&view=diff
==============================================================================
--- directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/operations/search/SearchIT.java
(original)
+++ directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/operations/search/SearchIT.java
Mon Mar  1 19:58:06 2010
@@ -20,6 +20,7 @@
 package org.apache.directory.server.core.operations.search;
 
 
+import static org.apache.directory.server.core.integ.IntegrationUtils.getRootContext;
 import static org.apache.directory.server.core.integ.IntegrationUtils.getSchemaContext;
 import static org.apache.directory.server.core.integ.IntegrationUtils.getSystemContext;
 import static org.junit.Assert.assertEquals;
@@ -55,8 +56,6 @@
 import org.apache.directory.shared.ldap.exception.LdapTimeLimitExceededException;
 import org.apache.directory.shared.ldap.ldif.LdifUtils;
 import org.apache.directory.shared.ldap.message.AliasDerefMode;
-import org.apache.directory.shared.ldap.message.SearchRequestImpl;
-import org.apache.directory.shared.ldap.message.internal.InternalSearchRequest;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -1738,5 +1737,104 @@
        assertNull( attrs.get( SchemaConstants.ENTRY_UUID_AT ) );
        assertNull( attrs.get( SchemaConstants.CREATORS_NAME_AT ) );
    }
+
+   
+   @Test
+   public void testSearchEmptyDNWithOneLevelScope() throws Exception
+   {
+       SearchControls controls = new SearchControls();
+       controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
+       controls.setDerefLinkFlag( false );
+       
+       LdapContext nullRootCtx = getRootContext( service );
+       
+       NamingEnumeration<SearchResult> list = nullRootCtx.search( "", "(objectClass=*)",
controls );
+       HashMap<String, Attributes> map = new HashMap<String, Attributes>();
+       
+       while ( list.hasMore() )
+       {
+           SearchResult result = list.next();
+           map.put( result.getName(), result.getAttributes() );
+       }
+       
+       assertEquals( 2, map.size() );
+       
+       assertTrue( map.containsKey( "ou=system" ) );
+       assertTrue( map.containsKey( "ou=schema" ) );
+   }
+   
+   
+   @Test
+   public void testSearchEmptyDNWithSubLevelScope() throws Exception
+   {
+       SearchControls controls = new SearchControls();
+       controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+       controls.setDerefLinkFlag( false );
+       
+       LdapContext nullRootCtx = getRootContext( service );
+       
+       NamingEnumeration<SearchResult> list = nullRootCtx.search( "", "(objectClass=organizationalUnit)",
controls );
+       HashMap<String, Attributes> map = new HashMap<String, Attributes>();
+       
+       while ( list.hasMore() )
+       {
+           SearchResult result = list.next();
+           map.put( result.getName(), result.getAttributes() );
+       }
+
+       assertTrue( map.size() > 2 );
+
+       assertTrue( map.containsKey( "ou=system" ) );
+       assertTrue( map.containsKey( "ou=schema" ) );
+   }
+   
+   
+   @Test
+   public void testSearchEmptyDNWithObjectScopeAndNoObjectClassPresenceFilter() throws Exception
+   {
+       SearchControls controls = new SearchControls();
+       controls.setSearchScope( SearchControls.OBJECT_SCOPE );
+       controls.setDerefLinkFlag( false );
+       
+       LdapContext nullRootCtx = getRootContext( service );
+       
+       NamingEnumeration<SearchResult> list = nullRootCtx.search( "", "(objectClass=domain)",
controls );
+       HashMap<String, Attributes> map = new HashMap<String, Attributes>();
+       
+       while ( list.hasMore() )
+       {
+           SearchResult result = list.next();
+           map.put( result.getName(), result.getAttributes() );
+       }
+       
+       assertEquals( 0, map.size() );
+       
+       assertFalse( map.containsKey( "ou=system" ) );
+       assertFalse( map.containsKey( "ou=schema" ) );
+   }
    
+   
+   @Test
+   public void testSearchEmptyDNWithOneLevelScopeAndNoObjectClassPresenceFilter() throws
Exception
+   {
+       SearchControls controls = new SearchControls();
+       controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
+       controls.setDerefLinkFlag( false );
+       
+       LdapContext nullRootCtx = getRootContext( service );
+       
+       NamingEnumeration<SearchResult> list = nullRootCtx.search( "", "(cn=*)", controls
);
+       HashMap<String, Attributes> map = new HashMap<String, Attributes>();
+       
+       while ( list.hasMore() )
+       {
+           SearchResult result = list.next();
+           map.put( result.getName(), result.getAttributes() );
+       }
+       
+       assertEquals( 0, map.size() );
+       
+       assertFalse( map.containsKey( "ou=system" ) );
+       assertFalse( map.containsKey( "ou=schema" ) );
+   }
 }

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java?rev=917683&r1=917682&r2=917683&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java
(original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/partition/DefaultPartitionNexus.java
Mon Mar  1 19:58:06 2010
@@ -46,6 +46,7 @@
 import org.apache.directory.server.core.entry.DefaultServerEntry;
 import org.apache.directory.server.core.entry.ServerEntry;
 import org.apache.directory.server.core.filtering.BaseEntryFilteringCursor;
+import org.apache.directory.server.core.filtering.CursorList;
 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
 import org.apache.directory.server.core.interceptor.context.AddContextPartitionOperationContext;
 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
@@ -81,6 +82,9 @@
 import org.apache.directory.shared.ldap.codec.search.controls.subentries.SubentriesControl;
 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
 import org.apache.directory.shared.ldap.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.cursor.Cursor;
+import org.apache.directory.shared.ldap.cursor.EmptyCursor;
+import org.apache.directory.shared.ldap.cursor.ListCursor;
 import org.apache.directory.shared.ldap.cursor.SingletonCursor;
 import org.apache.directory.shared.ldap.entry.EntryAttribute;
 import org.apache.directory.shared.ldap.entry.Value;
@@ -89,6 +93,7 @@
 import org.apache.directory.shared.ldap.exception.LdapNoSuchAttributeException;
 import org.apache.directory.shared.ldap.filter.ExprNode;
 import org.apache.directory.shared.ldap.filter.PresenceNode;
+import org.apache.directory.shared.ldap.filter.SearchScope;
 import org.apache.directory.shared.ldap.message.extended.NoticeOfDisconnect;
 import org.apache.directory.shared.ldap.name.LdapDN;
 import org.apache.directory.shared.ldap.schema.AttributeType;
@@ -727,6 +732,10 @@
         {
             boolean isObjectScope = searchCtls.getSearchScope() == SearchControls.OBJECT_SCOPE;
             
+            boolean isOnelevelScope = searchCtls.getSearchScope() == SearchControls.ONELEVEL_SCOPE;
+            
+            boolean isSublevelScope = searchCtls.getSearchScope() == SearchControls.SUBTREE_SCOPE;
+            
             // test for (objectClass=*)
             boolean isSearchAll = false;
             
@@ -831,6 +840,39 @@
     
                 return new BaseEntryFilteringCursor( new SingletonCursor<ServerEntry>(
serverEntry ), opContext );
             }
+            else if ( isObjectScope && ( ! isSearchAll ) )
+            {
+                return new BaseEntryFilteringCursor( new EmptyCursor<ServerEntry>(),
opContext );
+            }
+            else if( isOnelevelScope )
+            {
+                List<EntryFilteringCursor> cursors = new ArrayList<EntryFilteringCursor>();
+                for ( Partition p : partitions.values() )
+                {
+                    opContext.setDn( p.getSuffixDn() );
+                    opContext.setScope( SearchScope.OBJECT );
+                    cursors.add( p.search( opContext ) );
+                }
+                
+                return new CursorList( cursors, opContext );
+            }
+            else if ( isSublevelScope )
+            {
+                List<EntryFilteringCursor> cursors = new ArrayList<EntryFilteringCursor>();
+                for ( Partition p : partitions.values() )
+                {
+                    ClonedServerEntry entry = p.lookup( new LookupOperationContext( directoryService.getAdminSession(),
p.getSuffixDn() ) );
+                    if( entry != null )
+                    {
+                        Partition backend = getPartition( entry.getDn() );
+                        opContext.setDn( entry.getDn() );
+                        cursors.add( backend.search( opContext ) );
+                    }
+                }
+                
+                // don't feed the above Cursors' list to a BaseEntryFilteringCursor it is
skipping the naming context entry of each partition 
+                return new CursorList( cursors, opContext );
+            }
     
             // TODO : handle searches based on the RootDSE
             throw new LdapNameNotFoundException();



Mime
View raw message