You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by tc...@apache.org on 2007/05/16 23:57:59 UTC

svn commit: r538753 - in /jakarta/commons/proper/jci/trunk/core/src: main/java/org/apache/commons/jci/ main/java/org/apache/commons/jci/utils/ test/java/org/apache/commons/jci/

Author: tcurdt
Date: Wed May 16 14:57:58 2007
New Revision: 538753

URL: http://svn.apache.org/viewvc?view=rev&rev=538753
Log:
https://issues.apache.org/jira/browse/JCI-45


Added:
    jakarta/commons/proper/jci/trunk/core/src/test/java/org/apache/commons/jci/ReloadingClassLoaderRemoveTestCase.java   (with props)
Modified:
    jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/ReloadingClassLoader.java
    jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/utils/ConversionUtils.java

Modified: jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/ReloadingClassLoader.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/ReloadingClassLoader.java?view=diff&rev=538753&r1=538752&r2=538753
==============================================================================
--- jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/ReloadingClassLoader.java (original)
+++ jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/ReloadingClassLoader.java Wed May 16 14:57:58 2007
@@ -71,7 +71,7 @@
            
         // FIXME: this should be improved with a Map
         // find the pStore and index position with var i
-        while ( ( i <= n )  && ( stores[i] != pStore ) ) {
+        while ( ( i < n )  && ( stores[i] != pStore ) ) {
             i++;
         }
                     
@@ -81,17 +81,16 @@
         }
         
         // if stores length > 1 then array copy old values, else create new empty store 
-        if (n > 1) {            
-            final ResourceStore[] newStores = new ResourceStore[n - 1];
-            
-            System.arraycopy(stores, 0, newStores, 0, i-1);
-            System.arraycopy(stores, i, newStores, i, newStores.length - 1);
-            
-            stores = newStores;
-            delegate = new ResourceStoreClassLoader(parent, stores);
-        } else {
-            stores = new ResourceStore[0];
+        final ResourceStore[] newStores = new ResourceStore[n - 1];
+        if (i > 0) {
+            System.arraycopy(stores, 0, newStores, 0, i);
         }
+        if (i < n - 1) {
+            System.arraycopy(stores, i + 1, newStores, i, (n - i - 1));
+        }
+            
+        stores = newStores;
+        delegate = new ResourceStoreClassLoader(parent, stores);
         return true;
     }
     

Modified: jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/utils/ConversionUtils.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/utils/ConversionUtils.java?view=diff&rev=538753&r1=538752&r2=538753
==============================================================================
--- jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/utils/ConversionUtils.java (original)
+++ jakarta/commons/proper/jci/trunk/core/src/main/java/org/apache/commons/jci/utils/ConversionUtils.java Wed May 16 14:57:58 2007
@@ -21,6 +21,7 @@
 
 /**
  * Mainly common path manipultation helper methods
+ * NOT FOR USE OUTSIDE OF JCI
  * 
  * @author tcurdt
  */
@@ -61,6 +62,7 @@
         return new String(name);
     }
 
+/*
     public static String clazzName( final File base, final File file ) {
         final int rootLength = base.getAbsolutePath().length();
         final String absFileName = file.getAbsolutePath();
@@ -69,7 +71,7 @@
         final String clazzName = relFileName.replace(File.separatorChar, '.');
         return clazzName;
     }
-
+*/
     public static String relative( final File base, final File file ) {
         final int rootLength = base.getAbsolutePath().length();
         final String absFileName = file.getAbsolutePath();

Added: jakarta/commons/proper/jci/trunk/core/src/test/java/org/apache/commons/jci/ReloadingClassLoaderRemoveTestCase.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/jci/trunk/core/src/test/java/org/apache/commons/jci/ReloadingClassLoaderRemoveTestCase.java?view=auto&rev=538753
==============================================================================
--- jakarta/commons/proper/jci/trunk/core/src/test/java/org/apache/commons/jci/ReloadingClassLoaderRemoveTestCase.java (added)
+++ jakarta/commons/proper/jci/trunk/core/src/test/java/org/apache/commons/jci/ReloadingClassLoaderRemoveTestCase.java Wed May 16 14:57:58 2007
@@ -0,0 +1,262 @@
+/*
+ * 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.commons.jci;
+
+import junit.framework.TestCase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.commons.jci.classes.SimpleDump;
+import org.apache.commons.jci.stores.ResourceStore;
+import org.apache.commons.jci.stores.MemoryResourceStore;
+
+/**
+ * Test ReloadingClassLoader's <code>removeResourceStore({@link ResourceStore})</code>
+ * method.
+ */
+public class ReloadingClassLoaderRemoveTestCase extends TestCase {
+
+    private final Log log = LogFactory.getLog(ReloadingClassLoaderRemoveTestCase.class);
+    
+    private final byte[] clazzSimpleA;
+    private MemoryResourceStore store1 = new MemoryResourceStore();
+    private MemoryResourceStore store2 = new MemoryResourceStore();
+    private MemoryResourceStore store3 = new MemoryResourceStore();
+    private MemoryResourceStore store4 = new MemoryResourceStore();
+
+    public ReloadingClassLoaderRemoveTestCase() throws Exception {
+        clazzSimpleA = SimpleDump.dump("SimpleA");
+        assertTrue(clazzSimpleA.length > 0);
+    }
+
+    protected void setUp() throws Exception {
+        System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
+    }
+    
+    protected void tearDown() throws Exception {
+    }
+
+    /**
+     * Test trying to remove a ResourceStore from the ReloadingClassLoader
+     * which can't be found - when the ClassLoader contains NO other ResourceStore.
+     *
+     * Bug: The While loop in the removeResourceStore() throws an ArrayOutOfBoundsException
+     */
+    public void testRemoveStoreNotFoundClassLoaderNoStores() {
+        ReloadingClassLoader loader = new ReloadingClassLoader(getClass().getClassLoader());
+        checkRemoveResourceStore("No ResourceStore", loader, store1, false);
+    }
+
+    /**
+     * Test trying to remove a ResourceStore from the ReloadingClassLoader
+     * which can't be found - when the ClassLoader DOES contain other ResourceStore.
+     *
+     * Bug: The While loop in the removeResourceStore() throws an ArrayOutOfBoundsException
+     */
+    public void testRemoveStoreNotFoundClassLoaderHasStores() {
+        ReloadingClassLoader loader = new ReloadingClassLoader(getClass().getClassLoader());
+        loader.addResourceStore(store1);
+        loader.addResourceStore(store2);
+        checkRemoveResourceStore("Has ResourceStore", loader, store3, false);
+    }
+
+    /**
+     * Test trying to remove the first ResourceStore added
+     *
+     * Bug: ReloadingClassLoader addes ResourceStore at the start of the array. Removing the
+     *      first one added (last in array) causes the second System.arraycopy() statement to throw a
+     *      ArrayIndexOutOfBoundsException because the destination array position in the new smaller
+     *      array is too large.
+     */
+    public void testRemoveStoresOne() {
+        ReloadingClassLoader loader = new ReloadingClassLoader(getClass().getClassLoader());
+        loader.addResourceStore(store1);
+        loader.addResourceStore(store2);
+        loader.addResourceStore(store3);
+        loader.addResourceStore(store4);
+
+        checkRemoveResourceStore("One: Remove Store 1", loader, store1, true);
+        checkRemoveResourceStore("One: Store 1 Not Found", loader, store1, false);
+
+        checkRemoveResourceStore("One: Remove Store 2", loader, store2, true);
+        checkRemoveResourceStore("One: Store 2 Not Found", loader, store2, false);
+
+        checkRemoveResourceStore("One: Remove Store 3", loader, store3, true);
+        checkRemoveResourceStore("One: Store 3 Not Found", loader, store3, false);
+
+        checkRemoveResourceStore("One: Remove Store 4", loader, store4, true);
+        checkRemoveResourceStore("One: Store 4 Not Found", loader, store4, false);
+    }
+
+    /**
+     * Test trying to remove the second ResourceStore added
+     *
+     * Bug: ReloadingClassLoader addes ResourceStore at the start of the array. Removing the
+     *      first one added (last in array) causes the second System.arraycopy() statement to throw a
+     *      ArrayIndexOutOfBoundsException (??not sure why??)
+     */
+    public void testRemoveStoresTwo() {
+        ReloadingClassLoader loader = new ReloadingClassLoader(getClass().getClassLoader());
+        loader.addResourceStore(store1);
+        loader.addResourceStore(store2);
+        loader.addResourceStore(store3);
+        loader.addResourceStore(store4);
+
+        checkRemoveResourceStore("Two: Remove Store 2", loader, store2, true);
+        checkRemoveResourceStore("Two: Store 2 Not Found", loader, store2, false);
+
+        checkRemoveResourceStore("Two: Remove Store 4", loader, store4, true);
+        checkRemoveResourceStore("Two: Store 4 Not Found", loader, store4, false);
+
+        checkRemoveResourceStore("Two: Remove Store 3", loader, store3, true);
+        checkRemoveResourceStore("Two: Store 3 Not Found", loader, store3, false);
+
+        checkRemoveResourceStore("Two: Remove Store 1", loader, store1, true);
+        checkRemoveResourceStore("Two: Store 1 Not Found", loader, store1, false);
+    }
+
+    /**
+     * Test trying to remove the third ResourceStore added
+     *
+     * Bug: In this scenario the two System.arraycopy() statements don't copy the correct
+     *      ResourceStore - it creates a new array where the first resource store is null
+     *      and copies store3 and store2 to their same positions
+     */
+    public void testRemoveStoresThree() {
+        ReloadingClassLoader loader = new ReloadingClassLoader(getClass().getClassLoader());
+        loader.addResourceStore(store1);
+        loader.addResourceStore(store2);
+        loader.addResourceStore(store3);
+        loader.addResourceStore(store4);
+
+        checkRemoveResourceStore("Three: Remove Store 3", loader, store3, true);
+        checkRemoveResourceStore("Three: Store 3 Not Found", loader, store3, false);
+
+        checkRemoveResourceStore("Three: Remove Store 1", loader, store1, true);
+        checkRemoveResourceStore("Three: Store 1 Not Found", loader, store1, false);
+
+        checkRemoveResourceStore("Three: Remove Store 4", loader, store4, true);
+        checkRemoveResourceStore("Three: Store 4 Not Found", loader, store4, false);
+
+        checkRemoveResourceStore("Three: Remove Store 2", loader, store2, true);
+        checkRemoveResourceStore("Three: Store 2 Not Found", loader, store2, false);
+    }
+
+    /**
+     * Test trying to remove the fourth ResourceStore added
+     *
+     * Bug: ReloadingClassLoader addes ResourceStore at the start of the array. Removing the
+     *      last one added (first in array) causes the first System.arraycopy() statement to throw a
+     *      ArrayIndexOutOfBoundsException because the length to copy is -1
+     */
+    public void testRemoveStoresFour() {
+        ReloadingClassLoader loader = new ReloadingClassLoader(getClass().getClassLoader());
+        loader.addResourceStore(store1);
+        loader.addResourceStore(store2);
+        loader.addResourceStore(store3);
+        loader.addResourceStore(store4);
+
+        checkRemoveResourceStore("Four: Remove Store 4", loader, store4, true);
+        checkRemoveResourceStore("Four: Store 4 Not Found", loader, store4, false);
+
+        checkRemoveResourceStore("Four: Remove Store 3", loader, store3, true);
+        checkRemoveResourceStore("Four: Store 3 Not Found", loader, store3, false);
+
+        checkRemoveResourceStore("Four: Remove Store 2", loader, store2, true);
+        checkRemoveResourceStore("Four: Store 2 Not Found", loader, store2, false);
+
+        checkRemoveResourceStore("Four: Remove Store 1", loader, store1, true);
+        checkRemoveResourceStore("Four: Store 1 Not Found", loader, store1, false);
+    }
+
+
+    /**
+     * Test that a class can't be loaded after the ResourceStore containing
+     * it has been removed.
+     *
+     * Bug: When theres a single ResourceStore in the ClassLoader and its removed
+     *      a new "delegate" ClassLoader with the new ResourceStore array isn't being
+     *      created - which means that calling loadClass() still returns the classes
+     *      from the removed ResourceStore rather than throwing a ClassNotFoundException
+     */
+    public void testLoadClassAfterResourceStoreRemoved() {
+
+        // Create a class loader & add resource store
+        ReloadingClassLoader loader = new ReloadingClassLoader(this.getClass().getClassLoader());
+        MemoryResourceStore store = new MemoryResourceStore();
+        loader.addResourceStore(store);
+
+        // Check "jci.Simple" class can't be loaded
+        try {
+            Object simple1 = loader.loadClass("jci.Simple").newInstance();        
+            fail("Success loadClass[1]");
+        } catch(ClassNotFoundException e) {
+            // expected not found
+        } catch(Exception e) {
+            log.error(e);
+            fail("Error loadClass[1]: " + e);
+        }
+
+        // Add "jci.Simple" class to the resource store
+        String toStringValue = "FooBar";
+        try {
+            byte[] classBytes = SimpleDump.dump(toStringValue);
+            store.write("jci/Simple.class", classBytes);
+        } catch(Exception e) {
+            log.error(e);
+            fail("Error adding class to store: " + e);
+        }
+
+        // Check "jci.Simple" class can now be loaded
+        try {
+            Object simple2 = loader.loadClass("jci.Simple").newInstance();        
+            assertNotNull("Found loadClass[2]",  simple2);        
+            assertEquals("toString loadClass[2]",  toStringValue, simple2.toString());        
+        } catch(Exception e) {
+            log.error(e);
+            fail("Error loadClass[2]: " + e);
+        }
+
+        // Remove the resource store from the class loader
+        checkRemoveResourceStore("Remove Resource Store", loader, store, true);
+
+        // Test "jci.Simple" class can't be loaded after ResourceStore removed
+        try {
+            Object simple3 = loader.loadClass("jci.Simple").newInstance();        
+            fail("Success loadClass[3]");
+        } catch(ClassNotFoundException e) {
+            // expected not found
+        } catch(Exception e) {
+            log.error(e);
+            fail("Error loadClass[3]: " + e);
+        }
+
+    }
+
+    /**
+     * Check removing a ResourceStore from ReloadingClassLoader
+     */
+    private void checkRemoveResourceStore(String label, ReloadingClassLoader loader, ResourceStore store, boolean expected) {
+        try {
+            assertEquals(label, expected, loader.removeResourceStore(store));
+        } catch(Exception e) {
+            log.error(label, e);
+            fail(label + " failed: " + e);
+        }
+    }
+}

Propchange: jakarta/commons/proper/jci/trunk/core/src/test/java/org/apache/commons/jci/ReloadingClassLoaderRemoveTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/jci/trunk/core/src/test/java/org/apache/commons/jci/ReloadingClassLoaderRemoveTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision Author HeadURL Id

Propchange: jakarta/commons/proper/jci/trunk/core/src/test/java/org/apache/commons/jci/ReloadingClassLoaderRemoveTestCase.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org