You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by gt...@apache.org on 2011/06/03 22:37:26 UTC

svn commit: r1131212 - in /river/jtsk/skunk/surrogate: nbproject/ src/org/apache/river/container/ test/org/apache/river/container/

Author: gtrasuk
Date: Fri Jun  3 20:37:26 2011
New Revision: 1131212

URL: http://svn.apache.org/viewvc?rev=1131212&view=rev
Log:
Continued work on the container classloading infrastructure.  Now have settable-codebase class loader that uses jar files held in a commons-vfs file system, as will be required when loading classes from a surrogate jar without unpacking.

Added:
    river/jtsk/skunk/surrogate/nbproject/build-impl.xml~
      - copied unchanged from r1044769, incubator/river/jtsk/skunk/surrogate/nbproject/build-impl.xml
Modified:
    river/jtsk/skunk/surrogate/src/org/apache/river/container/LocalizedRuntimeException.java
    river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java
    river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties
    river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java
    river/jtsk/skunk/surrogate/src/org/apache/river/container/VirtualFileSystemClassLoader.java
    river/jtsk/skunk/surrogate/test/org/apache/river/container/VFSClassLoaderTest.java

Modified: river/jtsk/skunk/surrogate/src/org/apache/river/container/LocalizedRuntimeException.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/LocalizedRuntimeException.java?rev=1131212&r1=1131211&r2=1131212&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/src/org/apache/river/container/LocalizedRuntimeException.java (original)
+++ river/jtsk/skunk/surrogate/src/org/apache/river/container/LocalizedRuntimeException.java Fri Jun  3 20:37:26 2011
@@ -29,6 +29,18 @@ import java.util.ResourceBundle;
 public class LocalizedRuntimeException extends RuntimeException {
     private String messageBundleName;
     private String messageKey;
+
+    public String getMessageBundleName() {
+        return messageBundleName;
+    }
+
+    public String getMessageKey() {
+        return messageKey;
+    }
+
+    public Object[] getMessageParameters() {
+        return messageParameters;
+    }
     private Object[] messageParameters;
 
     /**
@@ -54,7 +66,7 @@ public class LocalizedRuntimeException e
     public LocalizedRuntimeException(Throwable rootCause,
             String messageBundleName,
             String messageKey,
-            Object[] messageParameters) {
+            Object ... messageParameters) {
         super(rootCause);
         this.messageBundleName=messageBundleName;
         this.messageKey=messageKey;

Modified: river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java?rev=1131212&r1=1131211&r2=1131212&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java (original)
+++ river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java Fri Jun  3 20:37:26 2011
@@ -52,6 +52,7 @@ public class MessageNames {
             ILLEGAL_ARGUMENT_EXCEPTION="illegalArgumentException",
             ILLEGAL_ACCESS_EXCEPTION="illegalAccessException",
             INITIALIZATION_EXCEPTION="initializationException",
+            INVALID_CLASSPATH_ENTRY="invalidClasspathEntry",
             INVOCATION_TARGET_EXCEPTION="invocationTargetException",
             INIT_METHOD_HAS_PARAMETERS="initMethodHasParameters",
             INIT_METHOD_NOT_VOID="initMethodIsntVoid",

Modified: river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties?rev=1131212&r1=1131211&r2=1131212&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties (original)
+++ river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties Fri Jun  3 20:37:26 2011
@@ -30,6 +30,7 @@ exceptionThrown=Exception thrown:
 failedDeployService=Deployment of service archive at ''{0}'' failed.
 illegalArgumentException=An operation threw an IllegalArgumentException.
 illegalAccessException=An operation threw an IllegalAccessException.
+invalidClasspathEntry=Invalid classpath entry: {0}
 invocationTargetException=An operation threw an InvocationTargetException.
 initializationException=An exception has occured while initializing the container.
 initMethodHasParameters=A method flagged as @Init must take no parameters.  \

Modified: river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java?rev=1131212&r1=1131211&r2=1131212&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java (original)
+++ river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java Fri Jun  3 20:37:26 2011
@@ -33,6 +33,8 @@ public class Strings {
             DASH = "-",
             DEFAULT = "default",
             DEFAULT_DISCOVERY_CONTEXT = "defaultDiscoveryContext",
+            DOT=".",
+            DOT_CLASS=".class",
             DOT_SSAR=".ssar",
             EMPTY = "",
             INIT_COMPLETE="initComplete",
@@ -42,6 +44,7 @@ public class Strings {
             PUT = "put",
             SSAR="ssar",
             SET = "set",
+            SLASH="/",
             TYPE="type",
             WHITESPACE_SEPARATORS=" \t\n\r",
             WORK="work";

Modified: river/jtsk/skunk/surrogate/src/org/apache/river/container/VirtualFileSystemClassLoader.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/VirtualFileSystemClassLoader.java?rev=1131212&r1=1131211&r2=1131212&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/src/org/apache/river/container/VirtualFileSystemClassLoader.java (original)
+++ river/jtsk/skunk/surrogate/src/org/apache/river/container/VirtualFileSystemClassLoader.java Fri Jun  3 20:37:26 2011
@@ -5,9 +5,16 @@
 
 package org.apache.river.container;
 
+import java.io.IOException;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import org.apache.commons.vfs.FileObject;
+import org.apache.commons.vfs.FileSystemException;
+import org.apache.commons.vfs.FileUtil;
 
 /**
  *
@@ -15,11 +22,114 @@ import org.apache.commons.vfs.FileObject
  */
 public class VirtualFileSystemClassLoader extends URLClassLoader {
 
+    private FileObject fileSystemRoot=null;
+
+    private List<FileObject> classpathFileObjects=new ArrayList<FileObject>();
+
     public VirtualFileSystemClassLoader(FileObject fileSystemRoot, ClassLoader parent) {
         super(new URL[0], parent);
+        this.fileSystemRoot=fileSystemRoot;
+    }
+
+    void addClassPathEntry(String fileName) {
+        try {
+            /* Classpath entry is a jar file. */
+            /* Create a nested file system from it and add it to the file objects.
+             */
+            FileObject entryObject = fileSystemRoot.resolveFile(fileName);
+            FileObject entryFileSystem=
+                    fileSystemRoot.getFileSystem().getFileSystemManager()
+                    .createFileSystem(entryObject);
+            classpathFileObjects.add(entryFileSystem);
+        } catch (FileSystemException ex) {
+            throw new LocalizedRuntimeException(ex, MessageNames.BUNDLE_NAME, MessageNames.INVALID_CLASSPATH_ENTRY, fileName);
+        }
     }
 
-    void addClassPathEntry(String string) {
+    /**
+     Find a resource by searching through all the classpath entries that have
+     been set up.
+     @param name
+     @return
+     */
+    @Override
+    public URL findResource(String name) {
+        try {
+            return findResourceFileObject(name).getURL();
+        } catch (FileSystemException ex) {
+            Logger.getLogger(VirtualFileSystemClassLoader.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        return null;
+    }
+
+    /**
+     Find the file object for a resource by searching through all the classpath
+     entries that have been set up.
+     @param name
+     @return
+     */
+    public FileObject findResourceFileObject(String name) {
+        for (FileObject cpFileSys:classpathFileObjects) {
+            try {
+                FileObject fo = cpFileSys.resolveFile(name);
+                if (fo!=null &&fo.isReadable()) {
+                    return fo;
+                }
+            } catch (FileSystemException ex) {
+                Logger.getLogger(VirtualFileSystemClassLoader.class.getName()).log(Level.SEVERE, null, ex);
+            }
+        }
+        return null;
+    }
 
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        String resourceName=name.replace(Strings.DOT, Strings.SLASH).concat(Strings.DOT_CLASS);
+        FileObject resourceFileObject=findResourceFileObject(resourceName);
+        if (resourceFileObject==null) {
+            throw new ClassNotFoundException(name+"(" + resourceName + ")");
+        }
+        try {
+            byte[] bytes=FileUtil.getContent(resourceFileObject);
+            return defineClass(name,bytes,0,bytes.length);
+        } catch(IOException ioe) {
+            throw new ClassNotFoundException(name, ioe);
+        }
     }
+
+    /**
+     * Set the codebase URLs to an arbitrary list of URLs.  These URLs form the
+     * codebase annotation for classes loaded through this classloader.
+     * For the sake of general paranoia, sets the codebase to a copy of the
+     * provided array.
+     * @param codebase
+     */
+    public void setCodebase(URL[] codebase) {
+        if (codebase == null || codebase.length==0) {
+            codebaseURLs = new URL[]{};
+            return;
+        }
+
+        codebaseURLs = new URL[codebase.length];
+        System.arraycopy(codebase, 0, codebaseURLs, 0, codebase.length);
+
+    }
+
+    /**
+     * Get the list of URLs that are used for the codebase annotation.
+     * Note that this list is not the actual classpath (that is in the
+     * superclass).  The codebase URLs are imposed to match whatever the Jini
+     * service wants to expose as its codebase annotation.
+     * @return
+     */
+    @Override
+    public URL[] getURLs() {
+        return codebaseURLs;
+    }
+
+    /** Stores the codebase that will be returned as the codebase annotation.
+     *
+     */
+    private URL codebaseURLs[] = new URL[0];
+
 }

Modified: river/jtsk/skunk/surrogate/test/org/apache/river/container/VFSClassLoaderTest.java
URL: http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/test/org/apache/river/container/VFSClassLoaderTest.java?rev=1131212&r1=1131211&r2=1131212&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/test/org/apache/river/container/VFSClassLoaderTest.java (original)
+++ river/jtsk/skunk/surrogate/test/org/apache/river/container/VFSClassLoaderTest.java Fri Jun  3 20:37:26 2011
@@ -4,6 +4,7 @@
  */
 package org.apache.river.container;
 
+import java.net.URL;
 import java.io.InputStream;
 import java.io.File;
 import org.apache.commons.vfs.FileObject;
@@ -23,8 +24,8 @@ import static org.junit.Assert.*;
 public class VFSClassLoaderTest {
 
     FileSystemManager fileSystemManager = null;
-    FileObject reggieModuleRoot=null;
-    ClassLoader extensionLoader=Bootstrap.class.getClassLoader().getParent();
+    FileObject reggieModuleRoot = null;
+    ClassLoader extensionLoader = Bootstrap.class.getClassLoader().getParent();
 
     public VFSClassLoaderTest() {
     }
@@ -39,58 +40,117 @@ public class VFSClassLoaderTest {
 
     @Before
     public void setUp() throws Exception {
-        fileSystemManager=VFS.getManager();
-        FileObject currentDir=fileSystemManager.toFileObject(new File("."));
-        FileObject reggieModuleJar=
+        fileSystemManager = VFS.getManager();
+        FileObject currentDir = fileSystemManager.toFileObject(new File("."));
+        FileObject reggieModuleJar =
                 currentDir.resolveFile("../../build/test/files/reggie-module.jar");
-        reggieModuleRoot=fileSystemManager.createFileSystem(reggieModuleJar);
+        reggieModuleRoot = fileSystemManager.createFileSystem(reggieModuleJar);
     }
 
     @After
     public void tearDown() {
-
     }
-    
+
     /**
-     Just to make sure that we have the base setup correct, ensure that we
-     can read the 'start.properties' file inside the reggie-module jar.
-     @throws Exception
+    Just to make sure that we have the base setup correct, ensure that we
+    can read the 'start.properties' file inside the reggie-module jar.
+    @throws Exception
      */
     @Test
     public void testCanReadStartDotProperties() throws Exception {
-        FileObject startProperties=reggieModuleRoot.resolveFile("start.properties");
+        FileObject startProperties = reggieModuleRoot.resolveFile("start.properties");
         assertNotNull(startProperties);
-        assertTrue("Properties file unreadable:" 
+        assertTrue("Properties file unreadable:"
                 + startProperties.toString() + " type=" + startProperties.getType(),
                 startProperties.isReadable());
     }
 
     /**
-     Create a VFSClassLoader and see if we can read a resource file from it.
-     As shown below, we're just adding a classpath entry with no filters or
-     codebase.
-     @throws Exception
+    Create a VFSClassLoader and make sure it throws an exception if we try
+    to add a non-existent jar file to it.
+    @throws Exception
+     */
+    @Test
+    public void testNonExistentJarFile() throws Exception {
+        VirtualFileSystemClassLoader UUT =
+                new VirtualFileSystemClassLoader(reggieModuleRoot, extensionLoader);
+        try {
+            UUT.addClassPathEntry("nonexistent.jar");
+            fail("Should have thrown an invalid classpath entry exception");
+        } catch (LocalizedRuntimeException ex) {
+            assertEquals(MessageNames.INVALID_CLASSPATH_ENTRY, ex.getMessageKey());
+        }
+    }
+
+    /**
+    Create a VFSClassLoader and see if we can read a resource file from it.
+    As shown below, we're just adding a classpath entry with no filters or
+    codebase.
+    @throws Exception
      */
     @Test
     public void testClassLoaderResourceLoading() throws Exception {
-        VirtualFileSystemClassLoader UUT=
+        VirtualFileSystemClassLoader UUT =
                 new VirtualFileSystemClassLoader(reggieModuleRoot, extensionLoader);
         UUT.addClassPathEntry("reggie.jar");
-        InputStream is=UUT.getResourceAsStream("META-INF/PREFERRED.LIST");
+        InputStream is = UUT.getResourceAsStream("META-INF/PREFERRED.LIST");
         assertNotNull("Failed to get resource stream for META-INF/PREFERRED.LIST",
                 is);
     }
 
+    /* Note to self- test for exception cases - bad fsroot, directory not jar, etc.
+     */
+
+    /**
+    The classloader should be able to load a class that's in the jar file,
+    and when we get an instance of that class, it should have the UUT
+    as its classloader.
+    @throws Exception
+     */
     @Test
     public void testClassLoading() throws Exception {
+        VirtualFileSystemClassLoader UUT =
+                new VirtualFileSystemClassLoader(reggieModuleRoot, extensionLoader);
+        UUT.addClassPathEntry("reggie.jar");
+        Class c = UUT.loadClass("com.sun.jini.reggie.ClassMapper");
+        assertNotNull(c);
+        assertTrue("Class had wrong classloader:" + c.getClassLoader(),
+                c.getClassLoader()==UUT);
+    }
 
-        fail("Write me. Should test that we can load a class.");
+    /**
+    The classloader should be able to load a class that's in the jar file,
+    and when we get an instance of that class, it should have the UUT
+    as its classloader.
+    @throws Exception
+     */
+    @Test
+    public void testParentClassLoading() throws Exception {
+        VirtualFileSystemClassLoader UUT =
+                new VirtualFileSystemClassLoader(reggieModuleRoot, extensionLoader);
+        UUT.addClassPathEntry("reggie.jar");
+        Class c = UUT.loadClass("java.util.List");
+        assertNotNull(c);
+        assertTrue("Class had wrong classloader:" + c.getClassLoader(),
+                c.getClassLoader()==null);
+        assertTrue("java.util.List".equals(c.getName()));
     }
 
     @Test
     public void testCodebaseAnnotation() throws Exception {
-        fail("Write me.  Should test that the codebase annotation can be set"
-                + " externally.");
+        VirtualFileSystemClassLoader UUT =
+                new VirtualFileSystemClassLoader(reggieModuleRoot, extensionLoader);
+        UUT.addClassPathEntry("reggie.jar");
+        /* At this point, there should be no urls on the reported codebase. */
+        URL[] actual=UUT.getURLs();
+        assertTrue("Should be no urls, but got " + Utils.format(actual),
+                actual.length==0);
+        URL[] a={ new URL("http://localhost:8080/a.jar")};
+        UUT.setCodebase(a);
+        actual=UUT.getURLs();
+        assertEquals("Should be one urls, but got " + Utils.format(actual),
+                1, actual.length);
+
     }
 
     @Test