summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorOlaf Otto2013-03-20 09:51:58 (EDT)
committer Glyn Normington2013-03-20 09:51:58 (EDT)
commitbdddfe8298f1c60ffc54098fe7bb98d9d63e3ff8 (patch)
tree7a9d0ea9fdc5e4f484cde38444fd91e8e8b4d891
parente552de0a5cf17cabdc2db9c8f9470d27dafa96c4 (diff)
downloadorg.eclipse.gemini.blueprint-bdddfe8298f1c60ffc54098fe7bb98d9d63e3ff8.zip
org.eclipse.gemini.blueprint-bdddfe8298f1c60ffc54098fe7bb98d9d63e3ff8.tar.gz
org.eclipse.gemini.blueprint-bdddfe8298f1c60ffc54098fe7bb98d9d63e3ff8.tar.bz2
384166: extend resource retrieval to both backing bundle and bridge classloader
-rw-r--r--core/src/main/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoader.java106
-rw-r--r--core/src/test/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoaderTest.java94
-rw-r--r--core/src/test/resources/org/eclipse/gemini/blueprint/util/internal/resource.txt1
3 files changed, 167 insertions, 34 deletions
diff --git a/core/src/main/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoader.java b/core/src/main/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoader.java
index f9052db..0b63f77 100644
--- a/core/src/main/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoader.java
+++ b/core/src/main/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoader.java
@@ -1,29 +1,30 @@
-/******************************************************************************
- * Copyright (c) 2006, 2010 VMware Inc., Oracle Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * and Apache License v2.0 which accompanies this distribution.
- * The Eclipse Public License is available at
- * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
- * is available at http://www.opensource.org/licenses/apache2.0.php.
- * You may elect to redistribute this code under either of these licenses.
- *
- * Contributors:
- * VMware Inc.
- * Oracle Inc.
- *****************************************************************************/
-
+/******************************************************************************
+ * Copyright (c) 2006, 2010 VMware Inc., Oracle Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
+ * is available at http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * VMware Inc.
+ * Oracle Inc.
+ *****************************************************************************/
+
package org.eclipse.gemini.blueprint.util;
-import java.io.IOException;
-import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Enumeration;
-
-import org.apache.commons.logging.Log;
-import org.osgi.framework.Bundle;
-import org.springframework.util.Assert;
+import org.apache.commons.logging.Log;
+import org.osgi.framework.Bundle;
+import org.springframework.util.Assert;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
/**
* ClassLoader backed by an OSGi bundle. Provides the ability to use a separate
@@ -40,6 +41,43 @@ import org.springframework.util.Assert;
*/
public class BundleDelegatingClassLoader extends ClassLoader {
+ private static final Enumeration<URL> EMPTY_RESOURCES = new Enumeration<URL>() {
+ public boolean hasMoreElements() {
+ return false;
+ }
+ public URL nextElement() {
+ throw new NoSuchElementException();
+ }
+ };
+
+ /**
+ * Transparently enumerates across two enumerations.
+ */
+ private static class CombinedEnumeration<T> implements Enumeration<T> {
+ private final Enumeration<T> e1;
+ private final Enumeration<T> e2;
+
+ public CombinedEnumeration(Enumeration<T> e1, Enumeration<T> e2) {
+ this.e1 = e1;
+ this.e2 = e2;
+ }
+
+ public boolean hasMoreElements() {
+ return e1.hasMoreElements() || e2.hasMoreElements();
+ }
+
+ public T nextElement() {
+ if (e1.hasMoreElements()) {
+ return e1.nextElement();
+ }
+ if (e2.hasMoreElements()) {
+ return e2.nextElement();
+ }
+
+ throw new NoSuchElementException();
+ }
+ }
+
/** use degradable logger */
private static final Log log = LogUtils.createLogger(BundleDelegatingClassLoader.class);
@@ -141,7 +179,25 @@ public class BundleDelegatingClassLoader extends ClassLoader {
return enm;
}
- public URL getResource(String name) {
+ @Override
+ public Enumeration<URL> getResources(String name) throws IOException {
+ @SuppressWarnings("unchecked")
+ Enumeration<URL> resources = this.backingBundle.getResources(name);
+
+ if (this.bridge != null) {
+ Enumeration<URL> bridgeResources = this.bridge.getResources(name);
+ if (resources == null) {
+ resources = bridgeResources;
+ } else if (bridgeResources != null){
+ resources = new CombinedEnumeration<URL>(resources, bridgeResources);
+ }
+ }
+
+ // Classloader contract: Never return null but rather an empty enumeration.
+ return resources != null ? resources : EMPTY_RESOURCES;
+ }
+
+ public URL getResource(String name) {
URL resource = findResource(name);
if (bridge != null && resource == null) {
resource = bridge.getResource(name);
diff --git a/core/src/test/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoaderTest.java b/core/src/test/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoaderTest.java
index 6eb7b08..b277531 100644
--- a/core/src/test/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoaderTest.java
+++ b/core/src/test/java/org/eclipse/gemini/blueprint/util/BundleDelegatingClassLoaderTest.java
@@ -14,16 +14,17 @@
package org.eclipse.gemini.blueprint.util;
-import java.net.URL;
-import java.util.Enumeration;
-
import junit.framework.TestCase;
-
import org.easymock.MockControl;
-import org.eclipse.gemini.blueprint.util.BundleDelegatingClassLoader;
import org.osgi.framework.Bundle;
import org.springframework.aop.framework.ProxyFactory;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+
+import static org.eclipse.gemini.blueprint.util.BundleDelegatingClassLoader.createBundleClassLoaderFor;
+
/**
* @author Costin Leau
*
@@ -36,11 +37,14 @@ public class BundleDelegatingClassLoaderTest extends TestCase {
private Bundle bundle;
+ private ClassLoader bridge;
+
protected void setUp() throws Exception {
bundleCtrl = MockControl.createStrictControl(Bundle.class);
bundle = (Bundle) bundleCtrl.getMock();
- classLoader =
- BundleDelegatingClassLoader.createBundleClassLoaderFor(bundle, ProxyFactory.class.getClassLoader());
+ classLoader = createBundleClassLoaderFor(bundle, ProxyFactory.class.getClassLoader());
+ bridge = getClass().getClassLoader();
+
bundleCtrl.reset();
}
@@ -56,8 +60,8 @@ public class BundleDelegatingClassLoaderTest extends TestCase {
assertFalse(classLoader.equals(new Object()));
assertEquals(classLoader, classLoader);
- assertTrue(classLoader.equals(BundleDelegatingClassLoader.createBundleClassLoaderFor(bundle, ProxyFactory.class
- .getClassLoader())));
+ assertTrue(classLoader.equals(createBundleClassLoaderFor(bundle, ProxyFactory.class
+ .getClassLoader())));
// assertEquals(bundle.hashCode(), clientClassLoader.hashCode());
}
@@ -100,4 +104,76 @@ public class BundleDelegatingClassLoaderTest extends TestCase {
assertSame(enumeration, classLoader.findResources(resource));
}
+
+ public void testGetResourcesFromBundleAndBridge() throws Exception {
+ final String resourceName = "org/eclipse/gemini/blueprint/util/internal/resource.txt";
+ final URL bundleURL = new URL("file://bundle/resourceName");
+
+ MockControl bundleResourcesControl = MockControl.createStrictControl(Enumeration.class);
+ Enumeration bundleResources = (Enumeration) bundleResourcesControl.getMock();
+ bundleResourcesControl.expectAndReturn(bundleResources.hasMoreElements(), true, 2);
+ bundleResourcesControl.expectAndReturn(bundleResources.nextElement(), bundleURL);
+ bundleResourcesControl.expectAndReturn(bundleResources.hasMoreElements(), false, 2);
+ bundleResourcesControl.replay();
+
+ bundleCtrl.expectAndReturn(bundle.getResources(resourceName), bundleResources);
+ bundleCtrl.replay();
+
+ Enumeration<URL> resources = createBundleClassLoaderFor(bundle, bridge).getResources(resourceName);
+
+ assertTrue(resources.hasMoreElements());
+ assertSame(bundleURL, resources.nextElement());
+
+ assertTrue(resources.hasMoreElements());
+ URL resource = resources.nextElement();
+ assertNotNull(resource);
+ assertTrue(resource.getFile().endsWith(resourceName));
+ }
+
+ public void testGetResourcesFromBundleOnly() throws Exception {
+ final String resourceName = "org/eclipse/gemini/blueprint/util/internal/resource.txt";
+ final URL bundleURL = new URL("file://bundle/resourceName");
+
+ MockControl bundleResourcesControl = MockControl.createStrictControl(Enumeration.class);
+ Enumeration bundleResources = (Enumeration) bundleResourcesControl.getMock();
+ bundleResourcesControl.expectAndReturn(bundleResources.hasMoreElements(), true);
+ bundleResourcesControl.expectAndReturn(bundleResources.nextElement(), bundleURL);
+ bundleResourcesControl.expectAndReturn(bundleResources.hasMoreElements(), false);
+ bundleResourcesControl.replay();
+
+ bundleCtrl.expectAndReturn(bundle.getResources(resourceName), bundleResources);
+ bundleCtrl.replay();
+
+ Enumeration<URL> resources = createBundleClassLoaderFor(bundle, null).getResources(resourceName);
+
+ assertTrue(resources.hasMoreElements());
+ assertSame(bundleURL, resources.nextElement());
+ assertFalse(resources.hasMoreElements());
+ }
+
+ public void testGetResourcesFromBridgeOnly() throws Exception {
+ final String resourceName = "org/eclipse/gemini/blueprint/util/internal/resource.txt";
+
+ bundleCtrl.expectAndReturn(bundle.getResources(resourceName), null);
+ bundleCtrl.replay();
+
+ Enumeration<URL> resources = createBundleClassLoaderFor(bundle, bridge).getResources(resourceName);
+ assertTrue(resources.hasMoreElements());
+ URL resource = resources.nextElement();
+ assertNotNull(resource);
+ assertTrue(resource.getFile().endsWith(resourceName));
+ assertFalse(resources.hasMoreElements());
+ }
+
+ public void testGetResourcesIsNullSafe() throws IOException {
+ final String resourceName = "org/eclipse/gemini/blueprint/util/internal/resource.txt";
+
+ bundleCtrl.expectAndReturn(bundle.getResources(resourceName), null);
+ bundleCtrl.replay();
+
+ Enumeration<URL> resources = createBundleClassLoaderFor(bundle, null).getResources(resourceName);
+
+ assertNotNull(resources);
+ assertFalse(resources.hasMoreElements());
+ }
} \ No newline at end of file
diff --git a/core/src/test/resources/org/eclipse/gemini/blueprint/util/internal/resource.txt b/core/src/test/resources/org/eclipse/gemini/blueprint/util/internal/resource.txt
new file mode 100644
index 0000000..b7e0de2
--- /dev/null
+++ b/core/src/test/resources/org/eclipse/gemini/blueprint/util/internal/resource.txt
@@ -0,0 +1 @@
+This is a test resource for the BundleDelegatingClassLoaderTest. \ No newline at end of file