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 );
+    }
+}