Author: rfeng
Date: Mon Jul 21 15:29:57 2008
New Revision: 678589
URL: http://svn.apache.org/viewvc?rev=678589&view=rev
Log:
Fix the a set of classloading related issues such as ClassNotFoundException,
ClassCastException and VerifyError
Modified:
tuscany/java/sca/modules/extensibility-osgi/src/main/java/org/apache/tuscany/sca/extensibility/osgi/OSGiServiceDiscoverer.java
tuscany/java/sca/modules/implementation-node-osgi-runtime/pom.xml
tuscany/java/sca/modules/implementation-node-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/node/osgi/launcher/LauncherBundleActivator.java
tuscany/java/sca/modules/implementation-node-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/node/osgi/LauncherBundleActivatorTestCase.java
Modified:
tuscany/java/sca/modules/extensibility-osgi/src/main/java/org/apache/tuscany/sca/extensibility/osgi/OSGiServiceDiscoverer.java
URL:
http://svn.apache.org/viewvc/tuscany/java/sca/modules/extensibility-osgi/src/main/java/org/apache/tuscany/sca/extensibility/osgi/OSGiServiceDiscoverer.java?rev=678589&r1=678588&r2=678589&view=diff
==============================================================================
---
tuscany/java/sca/modules/extensibility-osgi/src/main/java/org/apache/tuscany/sca/extensibility/osgi/OSGiServiceDiscoverer.java
(original)
+++
tuscany/java/sca/modules/extensibility-osgi/src/main/java/org/apache/tuscany/sca/extensibility/osgi/OSGiServiceDiscoverer.java
Mon Jul 21 15:29:57 2008
@@ -28,6 +28,8 @@
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 @@
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 @@
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);
Modified: tuscany/java/sca/modules/implementation-node-osgi-runtime/pom.xml
URL:
http://svn.apache.org/viewvc/tuscany/java/sca/modules/implementation-node-osgi-runtime/pom.xml?rev=678589&r1=678588&r2=678589&view=diff
==============================================================================
--- tuscany/java/sca/modules/implementation-node-osgi-runtime/pom.xml (original)
+++ tuscany/java/sca/modules/implementation-node-osgi-runtime/pom.xml Mon Jul
21 15:29:57 2008
@@ -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>
Modified:
tuscany/java/sca/modules/implementation-node-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/node/osgi/launcher/LauncherBundleActivator.java
URL:
http://svn.apache.org/viewvc/tuscany/java/sca/modules/implementation-node-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/node/osgi/launcher/LauncherBundleActivator.java?rev=678589&r1=678588&r2=678589&view=diff
==============================================================================
---
tuscany/java/sca/modules/implementation-node-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/node/osgi/launcher/LauncherBundleActivator.java
(original)
+++
tuscany/java/sca/modules/implementation-node-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/node/osgi/launcher/LauncherBundleActivator.java
Mon Jul 21 15:29:57 2008
@@ -27,20 +27,54 @@
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 @@
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 @@
}
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 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 @@
}
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 @@
}
+ 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 @@
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 @@
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 @@
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 @@
return version;
}
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void bundleChanged(BundleEvent event) {
+ }
+
}
Modified:
tuscany/java/sca/modules/implementation-node-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/node/osgi/LauncherBundleActivatorTestCase.java
URL:
http://svn.apache.org/viewvc/tuscany/java/sca/modules/implementation-node-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/node/osgi/LauncherBundleActivatorTestCase.java?rev=678589&r1=678588&r2=678589&view=diff
==============================================================================
---
tuscany/java/sca/modules/implementation-node-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/node/osgi/LauncherBundleActivatorTestCase.java
(original)
+++
tuscany/java/sca/modules/implementation-node-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/node/osgi/LauncherBundleActivatorTestCase.java
Mon Jul 21 15:29:57 2008
@@ -64,7 +64,9 @@
+ "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 @@
// 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 @@
}
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);
+ }
}