diff options
author | rfeng <rfeng@13f79535-47bb-0310-9956-ffa450edef68> | 2008-07-21 22:29:57 +0000 |
---|---|---|
committer | rfeng <rfeng@13f79535-47bb-0310-9956-ffa450edef68> | 2008-07-21 22:29:57 +0000 |
commit | fea70a868259d29d62d7cfba7a331149fd3109b2 (patch) | |
tree | 2a802e781935b8e0749d3240ff161f576d6d57ba /java/sca/modules | |
parent | f1d04ae9c2fa7e3f55dab43187b5015e17533e51 (diff) |
Fix the a set of classloading related issues such as ClassNotFoundException, ClassCastException and VerifyError
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@678589 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/sca/modules')
4 files changed, 209 insertions, 43 deletions
diff --git a/java/sca/modules/extensibility-osgi/src/main/java/org/apache/tuscany/sca/extensibility/osgi/OSGiServiceDiscoverer.java b/java/sca/modules/extensibility-osgi/src/main/java/org/apache/tuscany/sca/extensibility/osgi/OSGiServiceDiscoverer.java index 1d26d2891a..e90ded0901 100644 --- a/java/sca/modules/extensibility-osgi/src/main/java/org/apache/tuscany/sca/extensibility/osgi/OSGiServiceDiscoverer.java +++ b/java/sca/modules/extensibility-osgi/src/main/java/org/apache/tuscany/sca/extensibility/osgi/OSGiServiceDiscoverer.java @@ -28,6 +28,8 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.security.SecureClassLoader; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -48,9 +50,77 @@ import org.osgi.framework.BundleContext; public class OSGiServiceDiscoverer implements ServiceDiscoverer { private static final Logger logger = Logger.getLogger(OSGiServiceDiscoverer.class.getName()); private BundleContext context; + private ClassLoader classLoader; public OSGiServiceDiscoverer(BundleContext context) { this.context = context; + this.classLoader = new ClassLoaderImpl(); + } + + public class ClassLoaderImpl extends SecureClassLoader { + + public ClassLoaderImpl() { + super(OSGiServiceDiscoverer.class.getClassLoader()); + } + + /** + * Open a back-door to expose the META-INF/services resources + */ + @Override + protected URL findResource(String name) { + int index = name.lastIndexOf('/'); + if (index == -1) { + return null; + } + String path = name.substring(0, index); + if (path.startsWith("/")) { + path = path.substring(1); + } + + if (!path.startsWith("META-INF/services")) { + return null; + } + + for (Bundle bundle : context.getBundles()) { + URL url = bundle.getEntry(name); + if (url != null) { + return url; + } + } + + return null; + } + + /** + * Open a back-door to expose the META-INF/services resources + */ + @Override + protected Enumeration<URL> findResources(String name) throws IOException { + int index = name.lastIndexOf('/'); + if (index == -1) { + return null; + } + String path = name.substring(0, index); + String file = name.substring(index + 1); + if (path.startsWith("/")) { + path = path.substring(1); + } + + if (!path.startsWith("META-INF/services")) { + return null; + } + + Set<URL> urlSet = new HashSet<URL>(); + + for (Bundle bundle : context.getBundles()) { + Enumeration<URL> urls = bundle.findEntries(path, file, false); + if (urls != null) { + urlSet.addAll(Collections.list(urls)); + } + } + return Collections.enumeration(urlSet); + } + } public static class ServiceDeclarationImpl implements ServiceDeclaration { @@ -173,6 +243,14 @@ public class OSGiServiceDiscoverer implements ServiceDiscoverer { return attributes; } + /** + * This class loader can be set as the thread context class loader for non-OSGi code + * @return + */ + public ClassLoader getClassLoader() { + return classLoader; + } + @SuppressWarnings("unchecked") public Set<ServiceDeclaration> discover(String serviceName, boolean firstOnly) { boolean debug = logger.isLoggable(Level.FINE); diff --git a/java/sca/modules/implementation-node-osgi-runtime/pom.xml b/java/sca/modules/implementation-node-osgi-runtime/pom.xml index e301bf3a34..23836bb141 100644 --- a/java/sca/modules/implementation-node-osgi-runtime/pom.xml +++ b/java/sca/modules/implementation-node-osgi-runtime/pom.xml @@ -99,7 +99,7 @@ <goal>copy-dependencies</goal> </goals> <configuration> - <outputDirectory>${project.build.directory}/modules</outputDirectory> + <outputDirectory>${project.build.directory}/tuscany/modules</outputDirectory> <excludeArtifactIds></excludeArtifactIds> </configuration> </execution> diff --git a/java/sca/modules/implementation-node-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/node/osgi/launcher/LauncherBundleActivator.java b/java/sca/modules/implementation-node-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/node/osgi/launcher/LauncherBundleActivator.java index 8296da93b5..015ef5741d 100644 --- a/java/sca/modules/implementation-node-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/node/osgi/launcher/LauncherBundleActivator.java +++ b/java/sca/modules/implementation-node-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/node/osgi/launcher/LauncherBundleActivator.java @@ -27,20 +27,54 @@ import java.util.zip.ZipEntry; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleListener; import org.osgi.framework.Constants; /** * Bundle activator which installs Tuscany modules and 3rd party jars into an OSGi runtime. * */ -public class LauncherBundleActivator implements BundleActivator, Constants { - +public class LauncherBundleActivator implements BundleActivator, Constants, BundleListener { private static Logger logger = Logger.getLogger(LauncherBundleActivator.class.getName()); - private ArrayList<Bundle> tuscanyBundles = new ArrayList<Bundle>(); - private static final String[] immutableJars = {"bcprov"}; + private BundleContext bundleContext; + private List<Bundle> tuscanyBundles = new ArrayList<Bundle>(); + + public static String toString(Bundle b, boolean verbose) { + StringBuffer sb = new StringBuffer(); + sb.append(b.getBundleId()).append(" ").append(b.getSymbolicName()); + int s = b.getState(); + if ((s & Bundle.UNINSTALLED) != 0) { + sb.append(" UNINSTALLED"); + } + if ((s & Bundle.INSTALLED) != 0) { + sb.append(" INSTALLED"); + } + if ((s & Bundle.RESOLVED) != 0) { + sb.append(" RESOLVED"); + } + if ((s & Bundle.STARTING) != 0) { + sb.append(" STARTING"); + } + if ((s & Bundle.STOPPING) != 0) { + sb.append(" STOPPING"); + } + if ((s & Bundle.ACTIVE) != 0) { + sb.append(" ACTIVE"); + } + + if (verbose) { + sb.append(" ").append(b.getLocation()); + sb.append(" ").append(b.getHeaders()); + } + return sb.toString(); + } + public void start(BundleContext bundleContext) throws Exception { + this.bundleContext = bundleContext; + this.bundleContext.addBundleListener(this); installTuscany(bundleContext); } @@ -49,18 +83,20 @@ public class LauncherBundleActivator implements BundleActivator, Constants { try { bundle.stop(); } catch (Exception e) { - // Ignore error + logger.severe(e.toString()); } } for (Bundle bundle : tuscanyBundles) { try { + logger.info("Uninstalling bundle: " + toString(bundle, false)); bundle.uninstall(); } catch (Exception e) { - // Ignore error + logger.severe(e.toString()); } } - + this.bundleContext.removeBundleListener(this); + this.bundleContext = null; } public void installTuscany(BundleContext bundleContext) { @@ -82,12 +118,14 @@ public class LauncherBundleActivator implements BundleActivator, Constants { } try { Bundle bundle = createAndInstallBundle(bundleContext, file); - tuscanyBundles.add(bundle); + if (bundle != null) { + tuscanyBundles.add(bundle); + } } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); } } - + long end = System.currentTimeMillis(); logger.info("Tuscany bundles are installed in " + (end - start) + " ms."); @@ -130,11 +168,25 @@ public class LauncherBundleActivator implements BundleActivator, Constants { public Bundle createAndInstallBundle(BundleContext bundleContext, File bundleFile) throws Exception { logger.info("Installing bundle: " + bundleFile); long start = System.currentTimeMillis(); - String bundleLocation = bundleFile.toURI().toString(); - Manifest manifest = createBundleManifest(bundleFile); + Manifest manifest = readManifest(bundleFile); + boolean isOSGiBundle = manifest != null && manifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME) != null; + + if (!isOSGiBundle) { + manifest = updateBundleManifest(bundleFile, manifest); + } + + String symbolicName = manifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME); + String version = manifest.getMainAttributes().getValue(BUNDLE_VERSION); + Bundle bundle = findBundle(bundleContext, symbolicName, version); + if (bundle != null) { + logger.info("Bundle is already installed: " + symbolicName); + return null; + } + + String bundleLocation = bundleFile.toURI().toString(); InputStream inStream = null; - if (manifest != null) { + if (!isOSGiBundle) { // We need to repackage the bundle ByteArrayOutputStream out = new ByteArrayOutputStream(); JarOutputStream jarOut = new JarOutputStream(out, manifest); @@ -155,7 +207,7 @@ public class LauncherBundleActivator implements BundleActivator, Constants { } try { - Bundle bundle = bundleContext.installBundle(bundleLocation, inStream); + bundle = bundleContext.installBundle(bundleLocation, inStream); logger.info("Bundle installed in " + (System.currentTimeMillis() - start) + " ms: " + bundleLocation); return bundle; } finally { @@ -164,6 +216,23 @@ public class LauncherBundleActivator implements BundleActivator, Constants { } + private Bundle findBundle(BundleContext bundleContext, String symbolicName, String version) { + Bundle[] bundles = bundleContext.getBundles(); + if (version == null) { + version = "0.0.0"; + } + for (Bundle b : bundles) { + String v = (String)b.getHeaders().get(BUNDLE_VERSION); + if (v == null) { + v = "0.0.0"; + } + if (b.getSymbolicName().equals(symbolicName) && v.equals(version)) { + return b; + } + } + return null; + } + private void addFileToJar(File file, JarOutputStream jarOut) throws IOException { JarEntry ze = new JarEntry(file.getName()); jarOut.putNextEntry(ze); @@ -192,8 +261,7 @@ public class LauncherBundleActivator implements BundleActivator, Constants { jarIn.close(); } - private Manifest createBundleManifest(File jarFile) throws Exception { - + private Manifest readManifest(File jarFile) throws IOException { if (!jarFile.exists()) { return null; } @@ -205,11 +273,14 @@ public class LauncherBundleActivator implements BundleActivator, Constants { if (manifest == null) { // Create a new one if no Manifest is found manifest = new Manifest(); - } else { - Attributes attributes = manifest.getMainAttributes(); - if (attributes.getValue(BUNDLE_SYMBOLICNAME) != null) { - return null; - } + } + return manifest; + } + + private Manifest updateBundleManifest(File jarFile, Manifest manifest) throws Exception { + + if (!jarFile.exists()) { + return null; } // Check if we have an associated .mf file @@ -252,12 +323,12 @@ public class LauncherBundleActivator implements BundleActivator, Constants { if (attributes.getValue(BUNDLE_MANIFESTVERSION) == null) { attributes.putValue(BUNDLE_MANIFESTVERSION, "2"); } - + if (isImmutableJar && attributes.getValue(BUNDLE_CLASSPATH) == null) { attributes.putValue(BUNDLE_CLASSPATH, ".," + jarFileName); } - jar = new JarInputStream(new FileInputStream(jarFile)); + JarInputStream jar = new JarInputStream(new FileInputStream(jarFile)); HashSet<String> packages = getPackagesInJar(jarFileName, jar); jar.close(); String version = getJarVersion(jarFileName); @@ -341,4 +412,11 @@ public class LauncherBundleActivator implements BundleActivator, Constants { return version; } + public BundleContext getBundleContext() { + return bundleContext; + } + + public void bundleChanged(BundleEvent event) { + } + } diff --git a/java/sca/modules/implementation-node-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/node/osgi/LauncherBundleActivatorTestCase.java b/java/sca/modules/implementation-node-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/node/osgi/LauncherBundleActivatorTestCase.java index eb6eac78dd..50d1363887 100644 --- a/java/sca/modules/implementation-node-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/node/osgi/LauncherBundleActivatorTestCase.java +++ b/java/sca/modules/implementation-node-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/node/osgi/LauncherBundleActivatorTestCase.java @@ -64,7 +64,9 @@ public class LauncherBundleActivatorTestCase { + "javax.xml.transform.stream, " + "javax.xml.validation, " + "javax.xml.xpath, " + // Force the classes to be imported from the system bundle + "javax.xml.stream, " + + "javax.xml.stream.util, " + "javax.sql," + "org.w3c.dom, " + "org.xml.sax, " @@ -108,10 +110,10 @@ public class LauncherBundleActivatorTestCase { // Now start Felix instance. felix.start(); BundleContext context = felix.getBundleContext(); -// discoverer = new OSGiServiceDiscoverer(context); -// ServiceDiscovery.setServiceDiscoverer(discoverer); + // discoverer = new OSGiServiceDiscoverer(context); + // ServiceDiscovery.setServiceDiscoverer(discoverer); - System.setProperty("TUSCANY_HOME", "target"); + System.setProperty("TUSCANY_HOME", "target/tuscany"); activator = new LauncherBundleActivator(); activator.start(context); } @@ -140,26 +142,34 @@ public class LauncherBundleActivatorTestCase { } Bundle b1 = bundles.get("org.apache.tuscany.sca.extensibility.osgi"); Class<?> discovererClass = b1.loadClass(OSGiServiceDiscoverer.class.getName()); - Thread.currentThread().setContextClassLoader(discovererClass.getClassLoader()); - Constructor<?> ctor = discovererClass.getConstructor(BundleContext.class); Object discoverer = ctor.newInstance(felix.getBundleContext()); - Class<?> serviceDiscoveryClass = b1.loadClass(ServiceDiscovery.class.getName()); - Method set = serviceDiscoveryClass.getMethod("setServiceDiscoverer", discovererClass.getInterfaces()[0]); - set.invoke(null, discoverer); - - Bundle b2 = bundles.get("org.apache.tuscany.sca.node2.api"); - // b2.start(); - Class<?> factory = b2.loadClass(className); - Method newInstance = factory.getMethod("newInstance"); - Object instance = newInstance.invoke(null); - Method create = instance.getClass().getMethod("createSCANodeFromClassLoader", String.class, ClassLoader.class); - Object node = create.invoke(instance, "HelloWorld.composite", getClass().getClassLoader()); - Method start = node.getClass().getMethod("start"); - start.invoke(node); - Method stop = node.getClass().getMethod("stop"); - stop.invoke(node); + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + Method getCL = discovererClass.getMethod("getClassLoader"); + ClassLoader cl = (ClassLoader)getCL.invoke(discoverer); + Thread.currentThread().setContextClassLoader(cl); + + try { + Class<?> serviceDiscoveryClass = b1.loadClass(ServiceDiscovery.class.getName()); + Method set = serviceDiscoveryClass.getMethod("setServiceDiscoverer", discovererClass.getInterfaces()[0]); + set.invoke(null, discoverer); + + Bundle b2 = bundles.get("org.apache.tuscany.sca.node2.api"); + // b2.start(); + Class<?> factory = b2.loadClass(className); + Method newInstance = factory.getMethod("newInstance"); + Object instance = newInstance.invoke(null); + Method create = + instance.getClass().getMethod("createSCANodeFromClassLoader", String.class, ClassLoader.class); + Object node = create.invoke(instance, "HelloWorld.composite", getClass().getClassLoader()); + Method start = node.getClass().getMethod("start"); + start.invoke(node); + Method stop = node.getClass().getMethod("stop"); + stop.invoke(node); + } finally { + Thread.currentThread().setContextClassLoader(tccl); + } } |