[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