You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by er...@apache.org on 2006/03/08 14:31:53 UTC
svn commit: r384211 - in /directory/trunks/apacheds:
core-unit/src/test/java/org/apache/directory/server/core/sp/
core/src/main/java/org/apache/directory/server/core/sp/
Author: ersiner
Date: Wed Mar 8 05:31:52 2006
New Revision: 384211
URL: http://svn.apache.org/viewcvs?rev=384211&view=rev
Log:
Added a basic implementation of the Ldap Class Loader
Added a test case which includes both of the search methods available:
- first test finds the class entry somewhere in the DIT
- second test finds the class entry in a predetermined (via a configuration entry) location
Added:
directory/trunks/apacheds/core-unit/src/test/java/org/apache/directory/server/core/sp/
directory/trunks/apacheds/core-unit/src/test/java/org/apache/directory/server/core/sp/LdapClassLoaderTest.java
directory/trunks/apacheds/core/src/main/java/org/apache/directory/server/core/sp/
directory/trunks/apacheds/core/src/main/java/org/apache/directory/server/core/sp/LdapClassLoader.java
Added: directory/trunks/apacheds/core-unit/src/test/java/org/apache/directory/server/core/sp/LdapClassLoaderTest.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core-unit/src/test/java/org/apache/directory/server/core/sp/LdapClassLoaderTest.java?rev=384211&view=auto
==============================================================================
--- directory/trunks/apacheds/core-unit/src/test/java/org/apache/directory/server/core/sp/LdapClassLoaderTest.java (added)
+++ directory/trunks/apacheds/core-unit/src/test/java/org/apache/directory/server/core/sp/LdapClassLoaderTest.java Wed Mar 8 05:31:52 2006
@@ -0,0 +1,124 @@
+/*
+ * 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.directory.server.core.sp;
+
+
+import javax.naming.Context;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+
+import org.apache.directory.server.core.jndi.ServerLdapContext;
+import org.apache.directory.server.core.unit.AbstractAdminTestCase;
+import org.apache.directory.shared.ldap.util.Base64;
+
+
+/**
+ * Test case for LdapClassLoader.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$ $Date$
+ */
+public class LdapClassLoaderTest extends AbstractAdminTestCase
+{
+ private static final String HELLOWORLD_CLASS_BASE64 = "yv66vgAAADEAHQoABgAPCQAQABEIABIKABMAFAcAFQcAFgEABjxpbml0PgEAAygpV"
+ + "gEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzsp"
+ + "VgEAClNvdXJjZUZpbGUBAA9IZWxsb1dvcmxkLmphdmEMAAcACAcAFwwAGAAZAQAMSGVsbG8gV29"
+ + "ybGQhBwAaDAAbABwBAApIZWxsb1dvcmxkAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy"
+ + "9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZ"
+ + "WFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAUABgAAAAAAAgABAAcACAAB"
+ + "AAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAAAEACQALAAwAAQAJAAAAJQACAAEAAAA"
+ + "JsgACEgO2AASxAAAAAQAKAAAACgACAAAABQAIAAYAAQANAAAAAgAO";
+
+ private static final byte[] HELLOWORLD_CLASS_BYTES = Base64.decode( HELLOWORLD_CLASS_BASE64.toCharArray() );
+
+
+ protected void setUp() throws Exception
+ {
+ // bind to RootDSE
+ overrideEnvironment( Context.PROVIDER_URL, "" );
+ super.setUp();
+ }
+
+
+ public void testLdapClassLoaderWithClassLoadedAnywhere() throws Exception
+ {
+ // get default naming context to work on
+ ServerLdapContext defaultContext = ( ServerLdapContext ) sysRoot.lookup( "ou=system" );
+
+ // set up
+ Attributes attributes = new BasicAttributes( "objectClass", "top", true );
+ attributes.get( "objectClass" ).add( "javaClass" );
+ attributes.put( "fullyQualifiedClassName", "HelloWorld" );
+ attributes.put( "byteCode", HELLOWORLD_CLASS_BYTES );
+ defaultContext.createSubcontext( "fullyQualifiedClassName=HelloWorld", attributes );
+
+ // assert set up successfull
+ assertNotNull( defaultContext.lookup( "fullyQualifiedClassName=HelloWorld" ) );
+
+ // load the class
+ LdapClassLoader loader = new LdapClassLoader( ( ServerLdapContext ) ( sysRoot.lookup( "" ) ) );
+ Class clazz = loader.loadClass( "HelloWorld" );
+
+ // assert class loaded successfully
+ assertEquals( clazz.getName(), "HelloWorld" );
+ }
+
+
+ public void testLdapClassLoaderWithClassLoadedAtDefaultSearchSubtree() throws Exception
+ {
+
+ // get default naming context to work on
+ ServerLdapContext defaultContext = ( ServerLdapContext ) sysRoot.lookup( "ou=system" );
+
+ // create an extensible object for holding custom config data
+ Attributes classLoaderDefaultSearchContextConfig = new BasicAttributes();
+ Attribute objectClass = new BasicAttribute( "objectClass" );
+ objectClass.add( "top" );
+ objectClass.add( "extensibleObject" );
+
+ // create custom config entry
+ classLoaderDefaultSearchContextConfig.put( objectClass );
+ classLoaderDefaultSearchContextConfig.put( new BasicAttribute( "cn", "classLoaderDefaultSearchContext" ) );
+
+ // add a default search context to the configuration
+ classLoaderDefaultSearchContextConfig.put( new BasicAttribute( "classLoaderDefaultSearchContext", "ou=system" ) );
+
+ // add the configuration entry to the DIT
+ ServerLdapContext configContext = ( ServerLdapContext ) defaultContext.lookup( "ou=configuration" );
+ configContext.createSubcontext( "cn=classLoaderDefaultSearchContext", classLoaderDefaultSearchContextConfig );
+
+ // create a class holder entry and add it to the DIT
+ Attributes attributes = new BasicAttributes( "objectClass", "top", true );
+ attributes.get( "objectClass" ).add( "javaClass" );
+ attributes.put( "fullyQualifiedClassName", "HelloWorld" );
+ attributes.put( "byteCode", HELLOWORLD_CLASS_BYTES );
+ defaultContext.createSubcontext( "fullyQualifiedClassName=HelloWorld", attributes );
+
+ // assert set up successfull
+ assertNotNull( defaultContext.lookup( "fullyQualifiedClassName=HelloWorld" ) );
+
+ // load the class
+ LdapClassLoader loader = new LdapClassLoader( ( ServerLdapContext ) ( sysRoot.lookup( "" ) ) );
+ Class clazz = loader.loadClass( "HelloWorld" );
+
+ // assert class loaded successfully
+ assertEquals( clazz.getName(), "HelloWorld" );
+ }
+}
Added: directory/trunks/apacheds/core/src/main/java/org/apache/directory/server/core/sp/LdapClassLoader.java
URL: http://svn.apache.org/viewcvs/directory/trunks/apacheds/core/src/main/java/org/apache/directory/server/core/sp/LdapClassLoader.java?rev=384211&view=auto
==============================================================================
--- directory/trunks/apacheds/core/src/main/java/org/apache/directory/server/core/sp/LdapClassLoader.java (added)
+++ directory/trunks/apacheds/core/src/main/java/org/apache/directory/server/core/sp/LdapClassLoader.java Wed Mar 8 05:31:52 2006
@@ -0,0 +1,169 @@
+/*
+ * 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.directory.server.core.sp;
+
+
+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.directory.server.core.jndi.ServerLdapContext;
+import org.apache.directory.shared.ldap.filter.BranchNode;
+import org.apache.directory.shared.ldap.filter.LeafNode;
+import org.apache.directory.shared.ldap.filter.SimpleNode;
+import org.apache.directory.shared.ldap.name.LdapName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A class loader that loads classes from an LDAP DIT.
+ *
+ * <p>
+ * This loader looks for an configuration entry whose DN is
+ * determined by defaultSearchContextsConfig variable. If there is such
+ * an entry it gets the search contexts from the entry and searches the
+ * class to be loaded in those contexts.
+ * If there is no default search context configuration entry it searches
+ * the class in the whole DIT.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$ $Date$
+ */
+public class LdapClassLoader extends ClassLoader
+{
+ private static final Logger log = LoggerFactory.getLogger( LdapClassLoader.class );
+ public static String defaultSearchContextsConfig = "cn=classLoaderDefaultSearchContext,ou=configuration,ou=system";
+ private ServerLdapContext RootDSE;
+
+ public LdapClassLoader( ServerLdapContext RootDSE ) throws NamingException
+ {
+ this.RootDSE = ( ( ServerLdapContext ) RootDSE.lookup( "" ) );
+ }
+
+ private byte[] findClassInDIT( NamingEnumeration searchContexts, String name ) throws ClassNotFoundException
+ {
+ String currentSearchContextName = null;
+ ServerLdapContext currentSearchContext = null;
+ NamingEnumeration javaClassEntries = null;
+ byte[] classBytes = null;
+
+ BranchNode filter = new BranchNode( BranchNode.AND );
+ filter.addNode( new SimpleNode( "fullyQualifiedClassName", name, LeafNode.EQUALITY ) );
+ filter.addNode( new SimpleNode( "objectClass", "javaClass", LeafNode.EQUALITY ) );
+
+ SearchControls controls = new SearchControls();
+ controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+
+ try
+ {
+ while( searchContexts.hasMore() )
+ {
+ currentSearchContextName = ( String ) searchContexts.next();
+ currentSearchContext = ( ServerLdapContext ) RootDSE.lookup( currentSearchContextName );
+
+ javaClassEntries = currentSearchContext.search( new LdapName(), filter, controls );
+ if ( javaClassEntries.hasMore() ) // there should be only one!
+ {
+ SearchResult javaClassEntry = ( SearchResult ) javaClassEntries.next();
+ Attribute byteCode = javaClassEntry.getAttributes().get( "byteCode" );
+ classBytes = ( byte[] ) byteCode.get();
+ continue;
+ }
+ }
+ }
+ catch ( NamingException e )
+ {
+ throw new ClassNotFoundException();
+ }
+
+ return classBytes;
+ }
+
+ public Class findClass( String name ) throws ClassNotFoundException
+ {
+ byte[] classBytes = null;
+
+ NamingEnumeration defaultSearchContexts = null;
+ NamingEnumeration namingContexts = null;
+
+ ServerLdapContext defaultSearchContextsConfigContext = null;
+
+ try
+ {
+ try
+ {
+ defaultSearchContextsConfigContext =
+ ( ServerLdapContext ) RootDSE.lookup( defaultSearchContextsConfig );
+ }
+ catch ( NamingException e )
+ {
+ log.debug( "No configuration data found for class loader default search contexts." );
+ }
+
+ if ( defaultSearchContextsConfigContext != null )
+ {
+ defaultSearchContexts = defaultSearchContextsConfigContext
+ .getAttributes( "", new String[] { "classLoaderDefaultSearchContext" } )
+ .get( "classLoaderDefaultSearchContext" ).getAll();
+
+ try
+ {
+ classBytes = findClassInDIT( defaultSearchContexts, name );
+
+ log.debug( "Class " + name + " found under default search contexts." );
+ }
+ catch ( ClassNotFoundException e )
+ {
+ log.debug( "Class " + name + " could not be found under default search contexts." );
+ }
+ }
+
+ if ( classBytes == null )
+ {
+ namingContexts = RootDSE
+ .getAttributes( "", new String[] { "namingContexts" } )
+ .get( "namingContexts" ).getAll();
+
+ classBytes = findClassInDIT( namingContexts, name );
+ }
+ }
+ catch ( NamingException e )
+ {
+ String msg = "Encountered JNDI failure while searching directory for class: " + name;
+ log.error( msg, e );
+ throw new ClassNotFoundException( msg );
+ }
+ catch ( ClassNotFoundException e )
+ {
+ String msg = "Class " + name + " not found in DIT.";
+ log.warn( msg );
+ throw new ClassNotFoundException( msg );
+ }
+ finally
+ {
+ if ( defaultSearchContexts != null ) { try { defaultSearchContexts.close(); } catch( Exception e ) {} };
+ if ( namingContexts != null ) { try { namingContexts.close(); } catch( Exception e ) {} };
+ }
+
+ return defineClass( name, classBytes, 0, classBytes.length );
+ }
+}