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([EMAIL PROTECTED] 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: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]