[jboss-cvs] JBossAS SVN: r59533 - in projects/osgi/trunk: core/src/main/org/jboss/osgi/core and 3 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu Jan 11 11:30:13 EST 2007
Author: alesj
Date: 2007-01-11 11:30:02 -0500 (Thu, 11 Jan 2007)
New Revision: 59533
Added:
projects/osgi/trunk/core/src/main/org/jboss/osgi/core/support/
projects/osgi/trunk/core/src/main/org/jboss/osgi/core/support/BundleDelegatingClassLoader.java
Modified:
projects/osgi/trunk/core/core.iml
projects/osgi/trunk/deployment/deployment.iml
projects/osgi/trunk/deployment/src/main/org/jboss/osgi/deployers/BundleClassLoaderDeployer.java
Log:
bundle delegate class loader
Modified: projects/osgi/trunk/core/core.iml
===================================================================
--- projects/osgi/trunk/core/core.iml 2007-01-11 16:29:27 UTC (rev 59532)
+++ projects/osgi/trunk/core/core.iml 2007-01-11 16:30:02 UTC (rev 59533)
@@ -25,11 +25,11 @@
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
- <root url="jar://$MODULE_DIR$/../thirdparty/jboss/microcontainer/lib/jboss-microcontainer.jar!/" />
+ <root url="jar://$MODULE_DIR$/../thirdparty/jboss/common-core/lib/jboss-common-core.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/../thirdparty/jboss/microcontainer/lib/jboss-microcontainer-src.zip!/" />
+ <root url="jar://$MODULE_DIR$/../thirdparty/jboss/common-core/lib/jboss-common-core-sources.jar!/" />
</SOURCES>
</library>
</orderEntry>
@@ -58,11 +58,11 @@
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
- <root url="jar://$MODULE_DIR$/../thirdparty/jboss/microcontainer/lib/jboss-container.jar!/" />
+ <root url="jar://$MODULE_DIR$/../thirdparty/jboss/microcontainer/lib/jboss-microcontainer.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$MODULE_DIR$/../thirdparty/jboss/microcontainer/lib/jboss-container-src.zip!/" />
+ <root url="jar://$MODULE_DIR$/../thirdparty/jboss/microcontainer/lib/jboss-microcontainer-src.zip!/" />
</SOURCES>
</library>
</orderEntry>
@@ -75,24 +75,24 @@
<SOURCES />
</library>
</orderEntry>
- <orderEntry type="module-library" exported="">
+ <orderEntry type="module-library">
<library>
<CLASSES>
- <root url="jar://$MODULE_DIR$/../thirdparty/jboss/common-core/lib/jboss-common-core.jar!/" />
+ <root url="jar://$MODULE_DIR$/../thirdparty/felix/lib/felix.jar!/" />
</CLASSES>
<JAVADOC />
- <SOURCES>
- <root url="jar://$MODULE_DIR$/../thirdparty/jboss/common-core/lib/jboss-common-core-sources.jar!/" />
- </SOURCES>
+ <SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
- <root url="jar://$MODULE_DIR$/../thirdparty/felix/lib/felix.jar!/" />
+ <root url="jar://$MODULE_DIR$/../../microcontainer/container/output/lib/jboss-container.jar!/" />
</CLASSES>
<JAVADOC />
- <SOURCES />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/../../microcontainer/container/output/lib/jboss-container-src.zip!/" />
+ </SOURCES>
</library>
</orderEntry>
<orderEntryProperties />
Added: projects/osgi/trunk/core/src/main/org/jboss/osgi/core/support/BundleDelegatingClassLoader.java
===================================================================
--- projects/osgi/trunk/core/src/main/org/jboss/osgi/core/support/BundleDelegatingClassLoader.java 2007-01-11 16:29:27 UTC (rev 59532)
+++ projects/osgi/trunk/core/src/main/org/jboss/osgi/core/support/BundleDelegatingClassLoader.java 2007-01-11 16:30:02 UTC (rev 59533)
@@ -0,0 +1,446 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2006, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.osgi.core.support;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import org.jboss.logging.Logger;
+import org.jboss.osgi.core.platform.spi.BundleAdapter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/**
+ * ClassLoader backed by an OSGi bundle. Will use the Bundle class loading.
+ * Contains facilities for tracing classloading behavior so that issues can be
+ * easily resolved. Debugging can be enabled by setting the system property
+ *
+ * @author Adrian Colyer
+ * @author Andy Piper
+ * @author Costin Leau
+ * @author <a href="mailto:ales.justin at jboss.com">Ales Justin</a>
+ */
+public class BundleDelegatingClassLoader extends ClassLoader
+{
+ private static final Logger log = Logger.getLogger(BundleDelegatingClassLoader.class);
+
+ protected ClassLoader parent;
+ protected BundleAdapter bundleAdapter;
+
+ public static BundleDelegatingClassLoader createBundleClassLoaderFor(final BundleAdapter bundleAdapter)
+ {
+ return AccessController.doPrivileged(new PrivilegedAction<BundleDelegatingClassLoader>()
+ {
+ public BundleDelegatingClassLoader run()
+ {
+ return new BundleDelegatingClassLoader(bundleAdapter);
+ }
+ });
+ }
+
+ public static BundleDelegatingClassLoader createBundleClassLoaderFor(final BundleAdapter bundleAdapter, final ClassLoader parent)
+ {
+ return AccessController.doPrivileged(new PrivilegedAction<BundleDelegatingClassLoader>()
+ {
+ public BundleDelegatingClassLoader run()
+ {
+ return new BundleDelegatingClassLoader(bundleAdapter, parent);
+ }
+ });
+ }
+
+ private BundleDelegatingClassLoader(BundleAdapter bundleAdapter)
+ {
+ this(bundleAdapter, Logger.class.getClassLoader());
+ }
+
+ private BundleDelegatingClassLoader(BundleAdapter bundleAdapter, ClassLoader parentClassLoader)
+ {
+ super(parentClassLoader);
+ this.bundleAdapter = bundleAdapter;
+ this.parent = parentClassLoader;
+ }
+
+ protected Class findClass(String name) throws ClassNotFoundException
+ {
+ try
+ {
+ try
+ {
+ Bundle bundle = bundleAdapter.getUnderlyingBundle();
+ return bundle.loadClass(name);
+ }
+ catch (ClassNotFoundException ex)
+ {
+ return parent.loadClass(name);
+ }
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ if (log.isTraceEnabled())
+ {
+ traceClassLoading(name, null);
+ }
+ throw cnfe;
+ }
+ catch (NoClassDefFoundError ncdfe)
+ {
+ // This is almost always an error
+ if (log.isTraceEnabled())
+ {
+ // This is caused by a dependent class failure,
+ // so make sure we search for the right one.
+ String cname = ncdfe.getMessage().replace('/', '.');
+ traceClassLoading(cname, name);
+ }
+ throw ncdfe;
+ }
+ }
+
+ /**
+ * A best-guess attempt at figuring out why the class could not be found.
+ *
+ * @param name of the class we are trying to find.
+ */
+ private synchronized void traceClassLoading(String name, String root)
+ {
+ Bundle bundle = bundleAdapter.getUnderlyingBundle();
+ Dictionary dict = bundle.getHeaders();
+ String bname = dict.get(Constants.BUNDLE_NAME) + "(" + dict.get(Constants.BUNDLE_SYMBOLICNAME) + ")";
+ log.debug("Could not find class [" + name + "] required by [" + bname + "] scanning available bundles");
+
+ BundleContext context;
+ try
+ {
+ context = bundleAdapter.getBundleContext();
+ }
+ catch (Exception e)
+ {
+ log.warn("Unable to trace class loading due to BundleContext lookup exception.", e);
+ return;
+ }
+ String packageName = name.substring(0, name.lastIndexOf('.'));
+ // Reject global packages
+ if (name.indexOf('.') < 0)
+ {
+ log.debug("Class is not in a package, its unlikely that this will work");
+ return;
+ }
+ Version iversion = hasImport(bundle, packageName);
+ if (iversion != null)
+ {
+ log.debug("Class is correctly imported as version [" + iversion + "], checking providing bundles");
+ Bundle[] bundles = context.getBundles();
+ for (int i = 0; i < bundles.length; i++)
+ {
+ if (bundles[i].getBundleId() != bundle.getBundleId())
+ {
+ Version exported = checkBundleForClass(bundles[i], name, iversion);
+ // Everything looks ok, but is the root bundle importing the
+ // dependent class also?
+ if (exported != null && exported.equals(iversion) && root != null)
+ {
+ for (int j = 0; j < bundles.length; j++)
+ {
+ Version rootexport = hasExport(bundles[j], root.substring(0, root.lastIndexOf('.')));
+ if (rootexport != null)
+ {
+ // TODO -- this is very rough, check the bundle
+ // classpath also.
+ Version rootimport = hasImport(bundles[j], packageName);
+ if (rootimport == null || !rootimport.equals(iversion))
+ {
+ log.debug("Bundle [" + getBundleName(bundles[j]) + "] exports [" + root
+ + "] as version [" + rootexport
+ + "] but does not import dependent package [" + packageName
+ + "] at version [" + iversion + "]");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (hasExport(bundle, packageName) != null)
+ {
+ log.debug("Class is exported, checking this bundle");
+ checkBundleForClass(bundle, name, iversion);
+ }
+ }
+
+ private Version checkBundleForClass(Bundle bundle, String name, Version iversion)
+ {
+ String packageName = name.substring(0, name.lastIndexOf('.'));
+ Version hasExport = hasExport(bundle, packageName);
+
+ // log.info("Examining Bundle [" + bundle.getBundleId() + ": " + bname +
+ // "]");
+ // Check for version matching
+ if (hasExport != null && !hasExport.equals(iversion))
+ {
+ log.debug("Bundle [" + getBundleName(bundle) + "] exports [" + packageName + "] as version [" + hasExport
+ + "] but version [" + iversion + "] was required");
+ return hasExport;
+ }
+ // Do more detailed checks
+ String cname = name.substring(packageName.length() + 1) + ".class";
+ Enumeration e = bundle.findEntries("/" + packageName.replace('.', '/'), cname, false);
+ if (e == null)
+ {
+ if (hasExport != null)
+ {
+ URL url = checkBundleJarsForClass(bundle, name);
+ if (url != null)
+ {
+ log.debug("Bundle [" + getBundleName(bundle) + "] contains [" + cname + "] in embedded jar ["
+ + url.toString() + "] but exports the package");
+ }
+ else
+ {
+ log.debug("Bundle [" + getBundleName(bundle) + "] does not contain [" + cname
+ + "] but exports the package");
+ }
+ }
+
+ String root = "/";
+ String fileName = packageName;
+ if (packageName.lastIndexOf(".") >= 0)
+ {
+ root = root + packageName.substring(0, packageName.lastIndexOf(".")).replace('.', '/');
+ fileName = packageName.substring(packageName.lastIndexOf(".") + 1).replace('.', '/');
+ }
+ Enumeration pe = bundle.findEntries(root, fileName, false);
+ if (pe != null)
+ {
+ if (hasExport != null)
+ {
+ log.debug("Bundle [" + getBundleName(bundle) + "] contains package [" + packageName
+ + "] and exports it");
+ }
+ else
+ {
+ log.debug("Bundle [" + getBundleName(bundle) + "] contains package [" + packageName
+ + "] but does not export it");
+ }
+
+ }
+ }
+ // Found the resource, check that it is exported.
+ else
+ {
+ if (hasExport != null)
+ {
+ log.debug("Bundle [" + getBundleName(bundle) + "] contains resource [" + cname
+ + "] and it is correctly exported as version [" + hasExport + "]");
+ Class c = null;
+ try
+ {
+ c = bundle.loadClass(name);
+ }
+ catch (ClassNotFoundException e1)
+ {
+ }
+ log.debug("Bundle [" + getBundleName(bundle) + "] loadClass [" + cname + "] returns [" + c + "]");
+ }
+ else
+ {
+ log.debug("Bundle [" + getBundleName(bundle) + "] contains resource [" + cname
+ + "] but its package is not exported");
+ }
+ }
+ return hasExport;
+ }
+
+ private URL checkBundleJarsForClass(Bundle bundle, String name)
+ {
+ String cname = name.replace('.', '/') + ".class";
+ for (Enumeration e = bundle.findEntries("/", "*.jar", true); e != null && e.hasMoreElements();)
+ {
+ URL url = (URL) e.nextElement();
+ try
+ {
+ JarInputStream jin = new JarInputStream(url.openStream());
+ // Copy entries from the real jar to our virtual jar
+ for (JarEntry ze = jin.getNextJarEntry(); ze != null; ze = jin.getNextJarEntry())
+ {
+ if (ze.getName().equals(cname))
+ {
+ jin.close();
+ return url;
+ }
+ }
+ jin.close();
+ }
+ catch (IOException e1)
+ {
+ log.debug("Skipped " + url.toString() + ": " + e1.getMessage());
+ }
+ }
+ return null;
+ }
+
+ private Version hasImport(Bundle bundle, String packageName)
+ {
+ Dictionary dict = bundle.getHeaders();
+ // Check imports
+ String imports = (String) dict.get(Constants.IMPORT_PACKAGE);
+ Version v = getVersion(imports, packageName);
+ if (v != null)
+ {
+ return v;
+ }
+ // Check for dynamic imports
+ String dynimports = (String) dict.get(Constants.DYNAMICIMPORT_PACKAGE);
+ if (dynimports != null)
+ {
+ for (StringTokenizer strok = new StringTokenizer(dynimports, ","); strok.hasMoreTokens();)
+ {
+ StringTokenizer parts = new StringTokenizer(strok.nextToken(), ";");
+ String pkg = parts.nextToken().trim();
+ if (pkg.endsWith(".*") && packageName.startsWith(pkg.substring(0, pkg.length() - 2)) || pkg.equals("*"))
+ {
+ Version version = Version.emptyVersion;
+ for (; parts.hasMoreTokens();)
+ {
+ String modifier = parts.nextToken().trim();
+ if (modifier.startsWith("version"))
+ {
+ version = Version.parseVersion(modifier.substring(modifier.indexOf("=") + 1).trim());
+ }
+ }
+ return version;
+ }
+ }
+ }
+ return null;
+ }
+
+ private Version hasExport(Bundle bundle, String packageName)
+ {
+ Dictionary dict = bundle.getHeaders();
+ return getVersion((String) dict.get(Constants.EXPORT_PACKAGE), packageName);
+ }
+
+ // Pull out a version of the meta-data
+ private Version getVersion(String stmt, String packageName)
+ {
+ if (stmt != null)
+ {
+ for (StringTokenizer strok = new StringTokenizer(stmt, ","); strok.hasMoreTokens();)
+ {
+ StringTokenizer parts = new StringTokenizer(strok.nextToken(), ";");
+ String pkg = parts.nextToken().trim();
+ if (pkg.equals(packageName))
+ {
+ Version version = Version.emptyVersion;
+ for (; parts.hasMoreTokens();)
+ {
+ String modifier = parts.nextToken().trim();
+ if (modifier.startsWith("version"))
+ {
+ version = Version.parseVersion(modifier.substring(modifier.indexOf("=") + 1).trim());
+ }
+ }
+ return version;
+ }
+ }
+ }
+ return null;
+ }
+
+ private String getBundleName(Bundle bundle)
+ {
+ Dictionary dict = bundle.getHeaders();
+ String name = (String) dict.get(Constants.BUNDLE_NAME);
+ String sname = (String) dict.get(Constants.BUNDLE_SYMBOLICNAME);
+ return (sname != null ? sname : name) + " (" + bundle.getLocation() + ")";
+ }
+
+ protected URL findResource(String name)
+ {
+ if (log.isTraceEnabled())
+ log.trace("looking for resource " + name);
+ URL url = this.bundleAdapter.getUnderlyingBundle().getResource(name);
+
+ if (url != null && log.isTraceEnabled())
+ log.trace("found resource " + name + " at " + url);
+ return url;
+ }
+
+ protected Enumeration<URL> findResources(String name) throws IOException
+ {
+ if (log.isTraceEnabled())
+ log.trace("looking for resources " + name);
+
+ Enumeration enm = this.bundleAdapter.getUnderlyingBundle().getResources(name);
+
+ if (enm != null && enm.hasMoreElements() && log.isTraceEnabled())
+ log.trace("found resource " + name + " at " + enm);
+
+ return enm;
+ }
+
+ public URL getResource(String name)
+ {
+ return (parent == null) ? findResource(name) : super.getResource(name);
+ }
+
+ public Class loadClass(String name) throws ClassNotFoundException
+ {
+ return (parent == null) ? findClass(name) : super.loadClass(name);
+ }
+
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ return true;
+
+ if (!(o instanceof BundleDelegatingClassLoader))
+ return false;
+
+ final BundleDelegatingClassLoader bundleDelegatingClassLoader = (BundleDelegatingClassLoader) o;
+
+ if (bundleAdapter.equals(bundleDelegatingClassLoader.bundleAdapter))
+ return (parent == null || parent.equals(bundleDelegatingClassLoader.parent));
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ int hashCode = bundleAdapter.hashCode();
+ if (parent != null)
+ hashCode |= parent.hashCode();
+
+ return hashCode;
+ }
+
+}
Modified: projects/osgi/trunk/deployment/deployment.iml
===================================================================
--- projects/osgi/trunk/deployment/deployment.iml 2007-01-11 16:29:27 UTC (rev 59532)
+++ projects/osgi/trunk/deployment/deployment.iml 2007-01-11 16:30:02 UTC (rev 59533)
@@ -23,6 +23,17 @@
</SOURCES>
</library>
</orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../../vfs/dist/jboss-vfs.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="file://$MODULE_DIR$/../../vfs/src/main/java" />
+ </SOURCES>
+ </library>
+ </orderEntry>
<orderEntryProperties />
</component>
</module>
Modified: projects/osgi/trunk/deployment/src/main/org/jboss/osgi/deployers/BundleClassLoaderDeployer.java
===================================================================
--- projects/osgi/trunk/deployment/src/main/org/jboss/osgi/deployers/BundleClassLoaderDeployer.java 2007-01-11 16:29:27 UTC (rev 59532)
+++ projects/osgi/trunk/deployment/src/main/org/jboss/osgi/deployers/BundleClassLoaderDeployer.java 2007-01-11 16:30:02 UTC (rev 59533)
@@ -24,6 +24,7 @@
import org.jboss.deployers.plugins.deployers.helpers.AbstractTopLevelClassLoaderDeployer;
import org.jboss.deployers.spi.structure.DeploymentContext;
import org.jboss.osgi.core.platform.spi.BundleAdapter;
+import org.jboss.osgi.core.support.BundleDelegatingClassLoader;
/**
* Creates classloader from Bundle, BundleContext.
@@ -39,7 +40,8 @@
BundleAdapter bundleAdapter = context.getTransientAttachments().getAttachment(BundleAdapter.class);
if (bundleAdapter != null)
{
- ClassLoader bundleClassLoader = createClassLoader(bundleAdapter);
+ ClassLoader parentClassLoader = getParentClassLoader(context);
+ ClassLoader bundleClassLoader = createClassLoader(bundleAdapter, parentClassLoader);
if (bundleClassLoader != null)
{
context.setClassLoader(bundleClassLoader);
@@ -49,10 +51,21 @@
return loader;
}
- protected ClassLoader createClassLoader(BundleAdapter bundleAdapter)
+ private ClassLoader getParentClassLoader(DeploymentContext context)
{
- // todo
- return null;
+ return null; // TODO
}
+ protected ClassLoader createClassLoader(BundleAdapter bundleAdapter, ClassLoader parentClassLoader)
+ {
+ if (parentClassLoader != null)
+ {
+ return BundleDelegatingClassLoader.createBundleClassLoaderFor(bundleAdapter, parentClassLoader);
+ }
+ else
+ {
+ return BundleDelegatingClassLoader.createBundleClassLoaderFor(bundleAdapter);
+ }
+ }
+
}
More information about the jboss-cvs-commits
mailing list