You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2006/01/17 00:23:46 UTC
svn commit: r369600 - in /directory/trunks/apacheds:
core-unit/src/test/java/org/apache/ldap/server/jndi/
core/src/main/java/org/apache/ldap/server/enumeration/
core/src/main/java/org/apache/ldap/server/referral/
Author: akarasulu
Date: Mon Jan 16 15:23:37 2006
New Revision: 369600
URL: http://svn.apache.org/viewcvs?rev=369600&view=rev
Log:
finished up with search in general including continuation behavoir for JNDI provider
Added:
directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/enumeration/ReferralHandlingEnumeration.java (with props)
Modified:
directory/trunks/apacheds/core-unit/src/test/java/org/apache/ldap/server/jndi/ReferralTest.java
directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/referral/ReferralService.java
Modified: directory/trunks/apacheds/core-unit/src/test/java/org/apache/ldap/server/jndi/ReferralTest.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core-unit/src/test/java/org/apache/ldap/server/jndi/ReferralTest.java?rev=369600&r1=369599&r2=369600&view=diff
==============================================================================
--- directory/trunks/apacheds/core-unit/src/test/java/org/apache/ldap/server/jndi/ReferralTest.java (original)
+++ directory/trunks/apacheds/core-unit/src/test/java/org/apache/ldap/server/jndi/ReferralTest.java Mon Jan 16 15:23:37 2006
@@ -17,13 +17,16 @@
package org.apache.ldap.server.jndi;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
+import java.util.Map;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.ReferralException;
import javax.naming.directory.Attributes;
@@ -31,9 +34,13 @@
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
+import org.apache.ldap.common.exception.LdapNamingException;
+import org.apache.ldap.common.message.ResultCodeEnum;
import org.apache.ldap.common.name.LdapName;
import org.apache.ldap.server.unit.AbstractAdminTestCase;
@@ -426,8 +433,6 @@
checkAncestorReferrals( e );
}
}
-
-
/**
@@ -485,5 +490,474 @@
{
checkAncestorReferrals( e );
}
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a modify rdn interceptor operation (corresponds to a subset of the modify
+ * dn operation) with the parent context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testModifyRdnWithReferralParent() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an parent which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ td.refCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.refCtx.rename( "cn=alex karasulu", "cn=aok" );
+ fail( "Should fail here throwing a ReferralException" );
+ }
+ catch( ReferralException e )
+ {
+ checkParentReferrals( e );
+ }
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a modify rdn interceptor operation (corresponds to a subset of the modify
+ * dn operation) with an ancestor context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testModifyRdnWithReferralAncestor() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an ancestor which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ td.refCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.refCtx.rename( "cn=alex karasulu,ou=apache", "cn=aok,ou=apache" );
+ fail( "Should fail here throwing a ReferralException" );
+ }
+ catch( ReferralException e )
+ {
+ checkAncestorReferrals( e );
+ }
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a move interceptor operation (corresponds to a subset of the modify
+ * dn operation) with the parent context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testMoveWithReferralParent() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an parent which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ td.refCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.refCtx.rename( "cn=alex karasulu", "cn=alex karasulu,ou=groups" );
+ fail( "Should fail here throwing a ReferralException" );
+ }
+ catch( ReferralException e )
+ {
+ checkParentReferrals( e );
+ }
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a move interceptor operation (corresponds to a subset of the modify
+ * dn operation) with an ancestor context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testMoveWithReferralAncestor() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an ancestor which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ td.refCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.refCtx.rename( "cn=alex karasulu,ou=apache", "cn=alex karasulu,ou=groups" );
+ fail( "Should fail here throwing a ReferralException" );
+ }
+ catch( ReferralException e )
+ {
+ checkAncestorReferrals( e );
+ }
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a move interceptor operation (corresponds to a subset of the modify
+ * dn operation) with the parent context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testMoveWithReferralParent2() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an parent which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ td.refCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.refCtx.rename( "cn=alex karasulu", "cn=aok,ou=groups" );
+ fail( "Should fail here throwing a ReferralException" );
+ }
+ catch( ReferralException e )
+ {
+ checkParentReferrals( e );
+ }
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a move interceptor operation (corresponds to a subset of the modify
+ * dn operation) with an ancestor context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testMoveWithReferralAncestor2() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an ancestor which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ td.refCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.refCtx.rename( "cn=alex karasulu,ou=apache", "cn=aok,ou=groups" );
+ fail( "Should fail here throwing a ReferralException" );
+ }
+ catch( ReferralException e )
+ {
+ checkAncestorReferrals( e );
+ }
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a move interceptor operation (corresponds to a subset of the modify
+ * dn operation) with the parent context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testMoveWithReferralParentDest() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an parent which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ createLocalUser();
+ td.rootCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.rootCtx.rename( "cn=akarasulu", "cn=akarasulu,ou=users" );
+ fail( "Should fail here throwing a LdapNamingException with ResultCodeEnum = AFFECTSMULTIPLEDSAS" );
+ }
+ catch( LdapNamingException e )
+ {
+ assertTrue( e.getResultCode() == ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a move interceptor operation (corresponds to a subset of the modify
+ * dn operation) with an ancestor context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testMoveWithReferralAncestorDest() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an ancestor which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ createDeepLocalUser();
+ td.rootCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.rootCtx.rename( "cn=akarasulu,ou=deep", "cn=akarasulu,ou=users" );
+ fail( "Should fail here throwing a LdapNamingException with ResultCodeEnum = AFFECTSMULTIPLEDSAS" );
+ }
+ catch( LdapNamingException e )
+ {
+ assertTrue( e.getResultCode() == ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a move interceptor operation (corresponds to a subset of the modify
+ * dn operation) with the parent context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testMoveWithReferralParent2Dest() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an parent which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ createLocalUser();
+ td.rootCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.rootCtx.rename( "cn=akarasulu", "cn=aok,ou=users" );
+ fail( "Should fail here throwing a LdapNamingException with ResultCodeEnum = AFFECTSMULTIPLEDSAS" );
+ }
+ catch( LdapNamingException e )
+ {
+ assertTrue( e.getResultCode() == ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+ }
+
+
+ /**
+ * Checks for correct core behavoir when Context.REFERRAL is set to <b>throw</b>
+ * for a move interceptor operation (corresponds to a subset of the modify
+ * dn operation) with an ancestor context being a referral.
+ *
+ * @throws Exception if something goes wrong.
+ */
+ public void testMoveWithReferralAncestor2Dest() throws Exception
+ {
+ // -------------------------------------------------------------------
+ // Attempt to modify the last component of the entry's name which
+ // resides below an ancestor which is a referral. We should encounter
+ // referral errors when referral setting is set to throw.
+ // -------------------------------------------------------------------
+
+ createDeepLocalUser();
+ td.rootCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.rootCtx.rename( "cn=akarasulu,ou=deep", "cn=aok,ou=users" );
+ fail( "Should fail here throwing a LdapNamingException with ResultCodeEnum = AFFECTSMULTIPLEDSAS" );
+ }
+ catch( LdapNamingException e )
+ {
+ assertTrue( e.getResultCode() == ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+ }
+
+
+ public void createLocalUser() throws Exception
+ {
+ LdapContext userCtx = null;
+ Attributes referral = new BasicAttributes( "objectClass", "top", true );
+ referral.get( "objectClass" ).add( "person" );
+ referral.put( "cn", "akarasulu" );
+ referral.put( "sn", "karasulu" );
+
+ try { td.rootCtx.destroySubcontext( "uid=akarasulu" ); } catch( NameNotFoundException e ) {}
+ try
+ {
+ userCtx = ( LdapContext ) td.rootCtx.createSubcontext( "cn=akarasulu", referral );
+ }
+ catch( NameAlreadyBoundException e )
+ {
+ td.refCtx = ( LdapContext ) td.rootCtx.lookup( "cn=akarasulu" );
+ }
+ referral = userCtx.getAttributes( "" );
+ assertTrue( referral.get( "cn" ).contains( "akarasulu" ) );
+ assertTrue( referral.get( "sn" ).contains( "karasulu" ) );
+ }
+
+
+ public void createDeepLocalUser() throws Exception
+ {
+ LdapContext userCtx = null;
+ Attributes referral = new BasicAttributes( "objectClass", "top", true );
+ referral.get( "objectClass" ).add( "person" );
+ referral.put( "cn", "akarasulu" );
+ referral.put( "sn", "karasulu" );
+
+ try { td.rootCtx.destroySubcontext( "uid=akarasulu,ou=deep" ); } catch( NameNotFoundException e ) {}
+ try { td.rootCtx.destroySubcontext( "ou=deep" ); } catch( NameNotFoundException e ) {}
+ try
+ {
+ td.rootCtx.createSubcontext( "ou=deep" );
+ userCtx = ( LdapContext ) td.rootCtx.createSubcontext( "cn=akarasulu,ou=deep", referral );
+ }
+ catch( NameAlreadyBoundException e )
+ {
+ td.refCtx = ( LdapContext ) td.rootCtx.lookup( "cn=akarasulu,ou=deep" );
+ }
+ referral = userCtx.getAttributes( "" );
+ assertTrue( referral.get( "cn" ).contains( "akarasulu" ) );
+ assertTrue( referral.get( "sn" ).contains( "karasulu" ) );
+ }
+
+
+ public void testSearchBaseIsReferral() throws Exception
+ {
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+ td.rootCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.rootCtx.search( "ou=users", "(objectClass=*)", controls );
+ fail( "should never get here" );
+ }
+ catch( ReferralException e )
+ {
+ assertEquals( "ldap://fermi:10389/ou=users,ou=system??sub", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://hertz:10389/ou=users,dc=example,dc=com??sub", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://maxwell:10389/ou=users,ou=system??sub", e.getReferralInfo() );
+ assertFalse( e.skipReferral() );
+ }
+ }
+
+
+ public void testSearchBaseParentIsReferral() throws Exception
+ {
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope( SearchControls.OBJECT_SCOPE );
+ td.refCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.refCtx.search( "cn=alex karasulu", "(objectClass=*)", controls );
+ }
+ catch( ReferralException e )
+ {
+ assertEquals( "ldap://fermi:10389/cn=alex karasulu,ou=users,ou=system??base", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://hertz:10389/cn=alex karasulu,ou=users,dc=example,dc=com??base", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://maxwell:10389/cn=alex karasulu,ou=users,ou=system??base", e.getReferralInfo() );
+ assertFalse( e.skipReferral() );
+ }
+ }
+
+
+ public void testSearchBaseAncestorIsReferral() throws Exception
+ {
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope( SearchControls.OBJECT_SCOPE );
+ td.refCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ try
+ {
+ td.refCtx.search( "cn=alex karasulu,ou=apache", "(objectClass=*)", controls );
+ }
+ catch( ReferralException e )
+ {
+ assertEquals( "ldap://fermi:10389/cn=alex karasulu,ou=apache,ou=users,ou=system??base", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://hertz:10389/cn=alex karasulu,ou=apache,ou=users,dc=example,dc=com??base", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://maxwell:10389/cn=alex karasulu,ou=apache,ou=users,ou=system??base", e.getReferralInfo() );
+ assertFalse( e.skipReferral() );
+ }
+ }
+
+
+ public void testSearchContinuations() throws Exception
+ {
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+ NamingEnumeration list = td.rootCtx.search( "", "(objectClass=*)", controls );
+ Map results = new HashMap();
+ while ( list.hasMore() )
+ {
+ SearchResult result = ( SearchResult) list.next();
+ System.out.println( "name = " + result.getName() + " results .. " + result );
+ results.put ( result.getName(), result );
+ }
+
+ assertNotNull( results.get( "ou=users,ou=system" ) );
+
+ // -------------------------------------------------------------------
+ // Now we will throw exceptions when searching for referrals
+ // -------------------------------------------------------------------
+
+ td.rootCtx.addToEnvironment( Context.REFERRAL, "throw" );
+ list = td.rootCtx.search( "", "(objectClass=*)", controls );
+ results = new HashMap();
+
+ try
+ {
+ while ( list.hasMore() )
+ {
+ SearchResult result = ( SearchResult ) list.next();
+ System.out.println( "name = " + result.getName() + " results .. " + result );
+ results.put ( result.getName(), result );
+ }
+ }
+ catch( ReferralException e )
+ {
+ assertEquals( "ldap://fermi:10389/ou=users,ou=system??sub", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://hertz:10389/ou=users,dc=example,dc=com??sub", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://maxwell:10389/ou=users,ou=system??sub", e.getReferralInfo() );
+ assertFalse( e.skipReferral() );
+ }
+
+ assertNull( results.get( "ou=users" ) );
+
+ // try again but this time with single level scope
+
+ controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
+ list = td.rootCtx.search( "", "(objectClass=*)", controls );
+ results = new HashMap();
+
+ try
+ {
+ while ( list.hasMore() )
+ {
+ SearchResult result = ( SearchResult ) list.next();
+ System.out.println( "name = " + result.getName() + " results .. " + result );
+ results.put ( result.getName(), result );
+ }
+ }
+ catch( ReferralException e )
+ {
+ assertEquals( "ldap://fermi:10389/ou=users,ou=system??base", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://hertz:10389/ou=users,dc=example,dc=com??base", e.getReferralInfo() );
+ assertTrue( e.skipReferral() );
+ assertEquals( "ldap://maxwell:10389/ou=users,ou=system??base", e.getReferralInfo() );
+ assertFalse( e.skipReferral() );
+ }
+
+ assertNull( results.get( "ou=users" ) );
}
}
Added: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/enumeration/ReferralHandlingEnumeration.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/enumeration/ReferralHandlingEnumeration.java?rev=369600&view=auto
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/enumeration/ReferralHandlingEnumeration.java (added)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/enumeration/ReferralHandlingEnumeration.java Mon Jan 16 15:23:37 2006
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed 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.ldap.server.enumeration;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+import org.apache.ldap.common.codec.util.LdapURL;
+import org.apache.ldap.common.codec.util.LdapURLEncodingException;
+import org.apache.ldap.common.exception.LdapReferralException;
+import org.apache.ldap.common.name.DnParser;
+import org.apache.ldap.server.partition.DirectoryPartitionNexus;
+import org.apache.ldap.server.referral.ReferralLut;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A wrapper enumeration which saves referral entries to be returned last.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class ReferralHandlingEnumeration implements NamingEnumeration
+{
+ private static final String REF_ATTR = "ref";
+ private final Logger log = LoggerFactory.getLogger( ReferralHandlingEnumeration.class );
+ private final List referrals = new ArrayList();
+ private final NamingEnumeration underlying;
+ private final ReferralLut lut;
+ private final DnParser parser;
+ private final DirectoryPartitionNexus nexus;
+ private final boolean doThrow;
+ private final int scope;
+ private SearchResult prefetched;
+ private int refIndex = -1;
+
+
+ public ReferralHandlingEnumeration( NamingEnumeration underlying, ReferralLut lut, DnParser parser,
+ DirectoryPartitionNexus nexus, int scope, boolean doThrow ) throws NamingException
+ {
+ this.underlying = underlying;
+ this.parser = parser;
+ this.doThrow = doThrow;
+ this.lut = lut;
+ this.scope = scope;
+ this.nexus = nexus;
+ prefetch();
+ }
+
+
+ public void prefetch() throws NamingException
+ {
+ while ( underlying.hasMore() )
+ {
+ SearchResult result = ( SearchResult ) underlying.next();
+ Name dn = parser.parse( result.getName() );
+ if ( lut.isReferral( dn ) )
+ {
+ referrals.add( result );
+ continue;
+ }
+ prefetched = result;
+ return;
+ }
+
+ refIndex++;
+ prefetched = ( SearchResult ) referrals.get( refIndex );
+ if ( doThrow )
+ {
+ doReferralExceptionOnSearchBase();
+ }
+ }
+
+
+ public Object next() throws NamingException
+ {
+ SearchResult retval = prefetched;
+ prefetch();
+ return retval;
+ }
+
+
+ public boolean hasMore() throws NamingException
+ {
+ return underlying.hasMore() || refIndex < referrals.size();
+ }
+
+
+ public void close() throws NamingException
+ {
+ underlying.close();
+ referrals.clear();
+ prefetched = null;
+ refIndex = Integer.MAX_VALUE;
+ }
+
+
+ public boolean hasMoreElements()
+ {
+ try
+ {
+ return hasMore();
+ }
+ catch ( NamingException e )
+ {
+ log.error( "Naming enumeration failure. Closing enumeration early!", e );
+ try
+ {
+ close();
+ }
+ catch ( NamingException e1 )
+ {
+ log.error( "Naming enumeration failure. Failed to properly close enumeration!", e1 );
+ }
+ }
+
+ return false;
+ }
+
+
+ public Object nextElement()
+ {
+ try
+ {
+ return next();
+ }
+ catch ( NamingException e )
+ {
+ log.error( "NamingEnumeration closed prematurely without returning elements.", e );
+ }
+
+ throw new NoSuchElementException( "NamingEnumeration closed prematurely without returning elements." );
+ }
+
+
+ public void doReferralExceptionOnSearchBase() throws NamingException
+ {
+ // the refs attribute may be filtered out so we might need to lookup the entry
+ Attribute refs = prefetched.getAttributes().get( REF_ATTR );
+ if ( refs == null )
+ {
+ refs = nexus.lookup( parser.parse( prefetched.getName() ) ).get( REF_ATTR );
+ }
+
+ if ( refs == null )
+ {
+ throw new IllegalStateException( prefetched.getName()
+ + " does not seem like a referral but we're trying to handle it as one." );
+ }
+
+ List list = new ArrayList( refs.size() );
+ for ( int ii = 0; ii < refs.size(); ii++ )
+ {
+ String val = ( String ) refs.get( ii );
+
+ // need to add non-ldap URLs as-is
+ if ( ! val.startsWith( "ldap" ) )
+ {
+ list.add( val );
+ continue;
+ }
+
+ // parse the ref value and normalize the DN according to schema
+ LdapURL ldapUrl = new LdapURL();
+ try
+ {
+ ldapUrl.parse( val.toCharArray() );
+ }
+ catch ( LdapURLEncodingException e )
+ {
+ log.error( "Bad URL ("+ val +") for ref in " + prefetched.getName() + ". Reference will be ignored." );
+ }
+
+ StringBuffer buf = new StringBuffer();
+ buf.append( ldapUrl.getScheme() );
+ buf.append( ldapUrl.getHost() );
+ if ( ldapUrl.getPort() > 0 )
+ {
+ buf.append( ":" );
+ buf.append( ldapUrl.getPort() );
+ }
+ buf.append( "/" );
+ buf.append( ldapUrl.getDn() );
+ buf.append( "??" );
+
+ switch ( scope )
+ {
+ case( SearchControls.SUBTREE_SCOPE ):
+ buf.append( "sub" );
+ break;
+
+ // if we search for one level and encounter a referral then search
+ // must be continued at that node using base level search scope
+ case( SearchControls.ONELEVEL_SCOPE ):
+ buf.append( "base" );
+ break;
+ case( SearchControls.OBJECT_SCOPE ):
+ buf.append( "base" );
+ break;
+ default:
+ throw new IllegalStateException( "Unknown recognized search scope: " + scope );
+ }
+
+ list.add( buf.toString() );
+ }
+ LdapReferralException lre = new LdapReferralException( list );
+ throw lre;
+ }
+}
Propchange: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/enumeration/ReferralHandlingEnumeration.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/referral/ReferralService.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/referral/ReferralService.java?rev=369600&r1=369599&r2=369600&view=diff
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/referral/ReferralService.java (original)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/ldap/server/referral/ReferralService.java Mon Jan 16 15:23:37 2006
@@ -24,6 +24,7 @@
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import javax.naming.Context;
import javax.naming.Name;
@@ -51,6 +52,9 @@
import org.apache.ldap.server.DirectoryServiceConfiguration;
import org.apache.ldap.server.configuration.DirectoryPartitionConfiguration;
import org.apache.ldap.server.configuration.InterceptorConfiguration;
+import org.apache.ldap.server.enumeration.ReferralHandlingEnumeration;
+import org.apache.ldap.server.enumeration.SearchResultFilter;
+import org.apache.ldap.server.enumeration.SearchResultFilteringEnumeration;
import org.apache.ldap.server.interceptor.BaseInterceptor;
import org.apache.ldap.server.interceptor.NextInterceptor;
import org.apache.ldap.server.invocation.Invocation;
@@ -86,6 +90,7 @@
private static final String REF_ATTR = "ref";
private ReferralLut lut = new ReferralLut();
+ private DirectoryPartitionNexus nexus;
private DnParser parser;
private Hashtable env;
@@ -151,7 +156,7 @@
public void init( DirectoryServiceConfiguration dsConfig, InterceptorConfiguration cfg ) throws NamingException
{
- DirectoryPartitionNexus nexus = dsConfig.getPartitionNexus();
+ nexus = dsConfig.getPartitionNexus();
AttributeTypeRegistry atr = dsConfig.getGlobalRegistries().getAttributeTypeRegistry();
parser = new DnParser( new ConcreteNameComponentNormalizer( atr ) );
env = dsConfig.getEnvironment();
@@ -369,16 +374,83 @@
}
+ /* -----------------------------------------------------------------------
+ * Special handling instructions for ModifyDn operations:
+ * ======================================================
+ *
+ * From RFC 3296 here => http://www.ietf.org/rfc/rfc3296.txt
+ *
+ * 5.6.2 Modify DN
+ *
+ * If the newSuperior is a referral object or is subordinate to a
+ * referral object, the server SHOULD return affectsMultipleDSAs. If
+ * the newRDN already exists but is a referral object, the server SHOULD
+ * return affectsMultipleDSAs instead of entryAlreadyExists.
+ * -----------------------------------------------------------------------
+ */
+
+
public void move( NextInterceptor next, Name oldName, Name newParent ) throws NamingException
{
- next.move( oldName, newParent );
+ Invocation invocation = InvocationStack.getInstance().peek();
+ ServerLdapContext caller = ( ServerLdapContext ) invocation.getCaller();
+ String refval = ( String ) caller.getEnvironment().get( Context.REFERRAL );
+ Name newName = ( Name ) newParent.clone();
+ newName.add( oldName.get( oldName.size() - 1 ) );
+
+ // handle a normal modify without following referrals
+ if ( refval == null || refval.equals( IGNORE ) )
+ {
+ next.move( oldName, newParent );
+ if ( lut.isReferral( oldName ) )
+ {
+ lut.referralChanged( oldName, newName );
+ }
+ return;
+ }
- // update the lut of a referral is being moved
- if ( lut.isReferral( oldName ) )
+ if ( refval.equals( THROW ) )
+ {
+ Name farthestSrc = lut.getFarthestReferralAncestor( oldName );
+ Name farthestDst = lut.getFarthestReferralAncestor( newName ); // note will not return newName so safe
+ if ( farthestSrc == null && farthestDst == null && ! lut.isReferral( newName ) )
+ {
+ next.move( oldName, newParent );
+ if ( lut.isReferral( oldName ) )
+ {
+ lut.referralChanged( oldName, newName );
+ }
+ return;
+ }
+ else if ( farthestSrc != null )
+ {
+ Attributes referral = invocation.getProxy().lookup( farthestSrc, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
+ Attribute refs = referral.get( REF_ATTR );
+ doReferralException( farthestSrc, oldName, refs );
+ }
+ else if ( farthestDst != null )
+ {
+ throw new LdapNamingException( farthestDst + " ancestor is a referral for modifyDn on " + newName
+ + " so it affects multiple DSAs", ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+ else if ( lut.isReferral( newName ) )
+ {
+ throw new LdapNamingException( newName
+ + " exists and is a referral for modifyDn destination so it affects multiple DSAs",
+ ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+
+ throw new IllegalStateException( "If you get this exception the server's logic was flawed in handling a " +
+ "modifyDn operation while processing referrals. Report this as a bug!" );
+ }
+ else if ( refval.equals( FOLLOW ) )
+ {
+ throw new NotImplementedException( FOLLOW + " referral handling mode not implemented" );
+ }
+ else
{
- Name newName = ( Name ) newParent.clone();
- newName.add( oldName.get( oldName.size() - 1 ) );
- lut.referralChanged( oldName, newName );
+ throw new LdapNamingException( "Undefined value for " + Context.REFERRAL + " key: "
+ + refval, ResultCodeEnum.OTHER );
}
}
@@ -386,29 +458,132 @@
public void move( NextInterceptor next, Name oldName, Name newParent, String newRdn, boolean deleteOldRdn )
throws NamingException
{
- next.move( oldName, newParent, newRdn, deleteOldRdn );
+ Invocation invocation = InvocationStack.getInstance().peek();
+ ServerLdapContext caller = ( ServerLdapContext ) invocation.getCaller();
+ String refval = ( String ) caller.getEnvironment().get( Context.REFERRAL );
+ Name newName = ( Name ) newParent.clone();
+ newName.add( newRdn );
+
+ // handle a normal modify without following referrals
+ if ( refval == null || refval.equals( IGNORE ) )
+ {
+ next.move( oldName, newParent, newRdn, deleteOldRdn );
+ if ( lut.isReferral( oldName ) )
+ {
+ lut.referralChanged( oldName, newName );
+ }
+ return;
+ }
- // update the lut of a referral is being moved
- if ( lut.isReferral( oldName ) )
+ if ( refval.equals( THROW ) )
+ {
+ Name farthestSrc = lut.getFarthestReferralAncestor( oldName );
+ Name farthestDst = lut.getFarthestReferralAncestor( newName ); // safe to use - does not return newName
+ if ( farthestSrc == null && farthestDst == null && ! lut.isReferral( newName ) )
+ {
+ next.move( oldName, newParent, newRdn, deleteOldRdn );
+ if ( lut.isReferral( oldName ) )
+ {
+ lut.referralChanged( oldName, newName );
+ }
+ return;
+ }
+ else if ( farthestSrc != null )
+ {
+ Attributes referral = invocation.getProxy().lookup( farthestSrc, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
+ Attribute refs = referral.get( REF_ATTR );
+ doReferralException( farthestSrc, oldName, refs );
+ }
+ else if ( farthestDst != null )
+ {
+ throw new LdapNamingException( farthestDst + " ancestor is a referral for modifyDn on " + newName
+ + " so it affects multiple DSAs", ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+ else if ( lut.isReferral( newName ) )
+ {
+ throw new LdapNamingException( newName
+ + " exists and is a referral for modifyDn destination so it affects multiple DSAs",
+ ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+
+ throw new IllegalStateException( "If you get this exception the server's logic was flawed in handling a " +
+ "modifyDn operation while processing referrals. Report this as a bug!" );
+ }
+ else if ( refval.equals( FOLLOW ) )
{
- Name newName = ( Name ) newParent.clone();
- newName.add( newRdn );
- lut.referralChanged( oldName, newName );
+ throw new NotImplementedException( FOLLOW + " referral handling mode not implemented" );
+ }
+ else
+ {
+ throw new LdapNamingException( "Undefined value for " + Context.REFERRAL + " key: "
+ + refval, ResultCodeEnum.OTHER );
}
}
- public void modifyRdn( NextInterceptor next, Name oldName, Name newParent, String newRdn, boolean deleteOldRdn )
+ public void modifyRn( NextInterceptor next, Name oldName, String newRdn, boolean deleteOldRdn )
throws NamingException
{
- next.modifyRn( oldName, newRdn, deleteOldRdn );
+ Invocation invocation = InvocationStack.getInstance().peek();
+ ServerLdapContext caller = ( ServerLdapContext ) invocation.getCaller();
+ String refval = ( String ) caller.getEnvironment().get( Context.REFERRAL );
+ Name newName = ( Name ) oldName.clone();
+ newName.remove( oldName.size() - 1 );
+ newName.add( parser.parse( newRdn ).toString() );
- // update the lut of a referral is being renamed
- if ( lut.isReferral( oldName ) )
+ // handle a normal modify without following referrals
+ if ( refval == null || refval.equals( IGNORE ) )
+ {
+ next.modifyRn( oldName, newRdn, deleteOldRdn );
+ if ( lut.isReferral( oldName ) )
+ {
+ lut.referralChanged( oldName, newName );
+ }
+ return;
+ }
+
+ if ( refval.equals( THROW ) )
+ {
+ Name farthestSrc = lut.getFarthestReferralAncestor( oldName );
+ Name farthestDst = lut.getFarthestReferralAncestor( newName );
+ if ( farthestSrc == null && farthestDst == null && ! lut.isReferral( newName ) )
+ {
+ next.modifyRn( oldName, newRdn, deleteOldRdn );
+ if ( lut.isReferral( oldName ) )
+ {
+ lut.referralChanged( oldName, newName );
+ }
+ return;
+ }
+ if ( farthestSrc != null )
+ {
+ Attributes referral = invocation.getProxy().lookup( farthestSrc, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
+ Attribute refs = referral.get( REF_ATTR );
+ doReferralException( farthestSrc, oldName, refs );
+ }
+ else if ( farthestDst != null )
+ {
+ throw new LdapNamingException( farthestDst + " ancestor is a referral for modifyDn on " + newName
+ + " so it affects multiple DSAs", ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+ else if ( lut.isReferral( newName ) )
+ {
+ throw new LdapNamingException( newName
+ + " exists and is a referral for modifyDn destination so it affects multiple DSAs",
+ ResultCodeEnum.AFFECTSMULTIPLEDSAS );
+ }
+
+ throw new IllegalStateException( "If you get this exception the server's logic was flawed in handling a " +
+ "modifyDn operation while processing referrals. Report this as a bug!" );
+ }
+ else if ( refval.equals( FOLLOW ) )
+ {
+ throw new NotImplementedException( FOLLOW + " referral handling mode not implemented" );
+ }
+ else
{
- Name newName = ( Name ) newParent.clone();
- newName.add( newRdn );
- lut.referralChanged( oldName, newName );
+ throw new LdapNamingException( "Undefined value for " + Context.REFERRAL + " key: "
+ + refval, ResultCodeEnum.OTHER );
}
}
@@ -689,5 +864,189 @@
referral = parser.parse( r.getName() );
}
}
+ }
+
+
+ public NamingEnumeration search( NextInterceptor next, Name base, Map env, ExprNode filter,
+ SearchControls controls ) throws NamingException
+ {
+ Invocation invocation = InvocationStack.getInstance().peek();
+ ServerLdapContext caller = ( ServerLdapContext ) invocation.getCaller();
+ String refval = ( String ) caller.getEnvironment().get( Context.REFERRAL );
+
+ // handle a normal modify without following referrals
+ if ( refval == null || refval.equals( IGNORE ) )
+ {
+ return next.search( base, env, filter, controls );
+ }
+
+ if ( refval.equals( THROW ) )
+ {
+ if ( lut.isReferral( base ) )
+ {
+ Attributes referral = invocation.getProxy().lookup( base, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
+ Attribute refs = referral.get( REF_ATTR );
+ doReferralExceptionOnSearchBase( base, refs, controls.getSearchScope() );
+ }
+
+ Name farthest = lut.getFarthestReferralAncestor( base );
+ if ( farthest == null )
+ {
+ SearchResultFilteringEnumeration srfe = ( SearchResultFilteringEnumeration )
+ next.search( base, env, filter, controls );
+ return new ReferralHandlingEnumeration( srfe, lut, parser, nexus, controls.getSearchScope(), true );
+ }
+
+ Attributes referral = invocation.getProxy().lookup( farthest, DirectoryPartitionNexusProxy.LOOKUP_BYPASS );
+ Attribute refs = referral.get( REF_ATTR );
+ doReferralExceptionOnSearchBase( farthest, base, refs, controls.getSearchScope() );
+ throw new IllegalStateException( "Should never get here: shutting up compiler" );
+ }
+ else if ( refval.equals( FOLLOW ) )
+ {
+ throw new NotImplementedException( FOLLOW + " referral handling mode not implemented" );
+ }
+ else
+ {
+ throw new LdapNamingException( "Undefined value for " + Context.REFERRAL + " key: "
+ + refval, ResultCodeEnum.OTHER );
+ }
+ }
+
+
+ class ReferralFilter implements SearchResultFilter//, SearchResultEnumerationAppender
+ {
+ public boolean accept( Invocation invocation, SearchResult result, SearchControls controls ) throws NamingException
+ {
+ return false;
+ }
+ }
+
+
+ public void doReferralExceptionOnSearchBase( Name base, Attribute refs, int scope ) throws NamingException
+ {
+ // handle referral here
+ List list = new ArrayList( refs.size() );
+ for ( int ii = 0; ii < refs.size(); ii++ )
+ {
+ String val = ( String ) refs.get( ii );
+
+ // need to add non-ldap URLs as-is
+ if ( ! val.startsWith( "ldap" ) )
+ {
+ list.add( val );
+ continue;
+ }
+
+ // parse the ref value and normalize the DN according to schema
+ LdapURL ldapUrl = new LdapURL();
+ try
+ {
+ ldapUrl.parse( val.toCharArray() );
+ }
+ catch ( LdapURLEncodingException e )
+ {
+ log.error( "Bad URL ("+ val +") for ref in " + base + ". Reference will be ignored." );
+ }
+
+ StringBuffer buf = new StringBuffer();
+ buf.append( ldapUrl.getScheme() );
+ buf.append( ldapUrl.getHost() );
+ if ( ldapUrl.getPort() > 0 )
+ {
+ buf.append( ":" );
+ buf.append( ldapUrl.getPort() );
+ }
+ buf.append( "/" );
+ buf.append( ldapUrl.getDn() );
+ buf.append( "??" );
+
+ switch ( scope )
+ {
+ case( SearchControls.SUBTREE_SCOPE ):
+ buf.append( "sub" );
+ break;
+ case( SearchControls.ONELEVEL_SCOPE ):
+ buf.append( "one" );
+ break;
+ case( SearchControls.OBJECT_SCOPE ):
+ buf.append( "base" );
+ break;
+ default:
+ throw new IllegalStateException( "Unknown recognized search scope: " + scope );
+ }
+
+ list.add( buf.toString() );
+ }
+ LdapReferralException lre = new LdapReferralException( list );
+ throw lre;
+ }
+
+
+ public void doReferralExceptionOnSearchBase( Name farthest, Name targetUpdn, Attribute refs, int scope ) throws NamingException
+ {
+ // handle referral here
+ List list = new ArrayList( refs.size() );
+ for ( int ii = 0; ii < refs.size(); ii++ )
+ {
+ String val = ( String ) refs.get( ii );
+
+ // need to add non-ldap URLs as-is
+ if ( ! val.startsWith( "ldap" ) )
+ {
+ list.add( val );
+ continue;
+ }
+
+ // parse the ref value and normalize the DN according to schema
+ LdapURL ldapUrl = new LdapURL();
+ try
+ {
+ ldapUrl.parse( val.toCharArray() );
+ }
+ catch ( LdapURLEncodingException e )
+ {
+ log.error( "Bad URL ("+ val +") for ref in " + farthest + ". Reference will be ignored." );
+ }
+
+ Name urlDn = parser.parse( ldapUrl.getDn().toString() );
+ int diff = targetUpdn.size() - farthest.size();
+ Name extra = new LdapName();
+ for ( int jj = 0; jj < diff; jj++ )
+ {
+ extra.add( targetUpdn.get( farthest.size() + jj ) );
+ }
+
+ urlDn.addAll( extra );
+ StringBuffer buf = new StringBuffer();
+ buf.append( ldapUrl.getScheme() );
+ buf.append( ldapUrl.getHost() );
+ if ( ldapUrl.getPort() > 0 )
+ {
+ buf.append( ":" );
+ buf.append( ldapUrl.getPort() );
+ }
+ buf.append( "/" );
+ buf.append( urlDn );
+ buf.append( "??" );
+
+ switch ( scope )
+ {
+ case( SearchControls.SUBTREE_SCOPE ):
+ buf.append( "sub" );
+ break;
+ case( SearchControls.ONELEVEL_SCOPE ):
+ buf.append( "one" );
+ break;
+ case( SearchControls.OBJECT_SCOPE ):
+ buf.append( "base" );
+ break;
+ default:
+ throw new IllegalStateException( "Unknown recognized search scope: " + scope );
+ }
+ list.add( buf.toString() );
+ }
+ LdapReferralException lre = new LdapReferralException( list );
+ throw lre;
}
}