svn commit: r666957 - in /activemq/camel/trunk: camel-core/pom.xml camel-core/src/main/java/org/apache/camel/util/ResolverUtil.java pom.xml

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r666957 - in /activemq/camel/trunk: camel-core/pom.xml camel-core/src/main/java/org/apache/camel/util/ResolverUtil.java pom.xml

davsclaus-2
Author: davsclaus
Date: Wed Jun 11 22:23:21 2008
New Revision: 666957

URL: http://svn.apache.org/viewvc?rev=666957&view=rev
Log:
CAMEL-577: ResolverUtil able to load from osgi bundles. Thanks to Freeman Fang for the patch.

Modified:
    activemq/camel/trunk/camel-core/pom.xml
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/util/ResolverUtil.java
    activemq/camel/trunk/pom.xml

Modified: activemq/camel/trunk/camel-core/pom.xml
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/pom.xml?rev=666957&r1=666956&r2=666957&view=diff
==============================================================================
--- activemq/camel/trunk/camel-core/pom.xml (original)
+++ activemq/camel/trunk/camel-core/pom.xml Wed Jun 11 22:23:21 2008
@@ -84,6 +84,11 @@
       <version>${spring-version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <version>${felix-osgi-version}</version>
+    </dependency>
   </dependencies>
 
 

Modified: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/util/ResolverUtil.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/util/ResolverUtil.java?rev=666957&r1=666956&r2=666957&view=diff
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/util/ResolverUtil.java (original)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/util/ResolverUtil.java Wed Jun 11 22:23:21 2008
@@ -20,6 +20,7 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
 import java.net.URL;
 import java.net.URLDecoder;
 import java.util.Arrays;
@@ -31,6 +32,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.Bundle;
 
 /**
  * <p>
@@ -40,7 +42,7 @@
  * specific annotation. However, through the use of the {@link Test} class it is
  * possible to search using arbitrary conditions.
  * </p>
- *
+ * <p/>
  * <p>
  * A ClassLoader is used to locate all locations (directories and jar files) in
  * the class path that contain classes within certain packages, and then to load
@@ -49,7 +51,7 @@
  * be overridden by calling {@link #setClassLoaders(Set)} prior to
  * invoking any of the {@code find()} methods.
  * </p>
- *
+ * <p/>
  * <p>
  * General searches are initiated by calling the
  * {@link #find(ResolverUtil.Test, String)} ()} method and supplying a package
@@ -59,11 +61,11 @@
  * for extensions of particular classes, or classes annotated with a specific
  * annotation.
  * </p>
- *
+ * <p/>
  * <p>
  * The standard usage pattern for the ResolverUtil class is as follows:
  * </p>
- *
+ * <p/>
  * <pre>
  * esolverUtil&lt;ActionBean&gt; resolver = new ResolverUtil&lt;ActionBean&gt;();
  * esolver.findImplementation(ActionBean.class, pkg1, pkg2);
@@ -147,7 +149,9 @@
         }
     }
 
-    /** The set of matches being accumulated. */
+    /**
+     * The set of matches being accumulated.
+     */
     private Set<Class<? extends T>> matches = new HashSet<Class<? extends T>>();
 
     /**
@@ -171,7 +175,7 @@
     /**
      * Returns the classloaders that will be used for scanning for classes. If no
      * explicit ClassLoader has been set by the calling, the context class
-     * loader will be used.
+     * loader will and the one that has loaded this class ResolverUtil be used.
      *
      * @return the ClassLoader instances that will be used to scan for classes
      */
@@ -179,6 +183,7 @@
         if (classLoaders == null) {
             classLoaders = new HashSet<ClassLoader>();
             classLoaders.add(Thread.currentThread().getContextClassLoader());
+            classLoaders.add(ResolverUtil.class.getClassLoader());
         }
         return classLoaders;
     }
@@ -200,44 +205,58 @@
      * collected. Accumulated classes can be accessed by calling
      * {@link #getClasses()}.
      *
-     * @param parent the class of interface to find subclasses or
-     *                implementations of
+     * @param parent       the class of interface to find subclasses or
+     *                     implementations of
      * @param packageNames one or more package names to scan (including
-     *                subpackages) for classes
+     *                     subpackages) for classes
      */
     public void findImplementations(Class parent, String... packageNames) {
         if (packageNames == null) {
             return;
         }
 
-        LOG.debug("Searching for implementations of " + parent.getName() + " in packages: " + Arrays.asList(packageNames));
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Searching for implementations of " + parent.getName() + " in packages: " + Arrays
+                .asList(packageNames));
+        }
 
         Test test = new IsA(parent);
         for (String pkg : packageNames) {
             find(test, pkg);
         }
 
-        LOG.debug("Found: " + getClasses());
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Found: " + getClasses());
+        }
     }
 
     /**
      * Attempts to discover classes that are annotated with to the annotation.
      * Accumulated classes can be accessed by calling {@link #getClasses()}.
      *
-     * @param annotation the annotation that should be present on matching
-     *                classes
+     * @param annotation   the annotation that should be present on matching
+     *                     classes
      * @param packageNames one or more package names to scan (including
-     *                subpackages) for classes
+     *                     subpackages) for classes
      */
     public void findAnnotated(Class<? extends Annotation> annotation, String... packageNames) {
         if (packageNames == null) {
             return;
         }
 
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Searching for annotations of " + annotation.getName() + " in packages: " + Arrays
+                .asList(packageNames));
+        }
+
         Test test = new AnnotatedWith(annotation);
         for (String pkg : packageNames) {
             find(test, pkg);
         }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Found: " + getClasses());
+        }
     }
 
     /**
@@ -246,26 +265,42 @@
      * and if the Test returns true the class is retained. Accumulated classes
      * can be fetched by calling {@link #getClasses()}.
      *
-     * @param test an instance of {@link Test} that will be used to filter
-     *                classes
+     * @param test        an instance of {@link Test} that will be used to filter
+     *                    classes
      * @param packageName the name of the package from which to start scanning
-     *                for classes, e.g. {@code net.sourceforge.stripes}
+     *                    for classes, e.g. {@code net.sourceforge.stripes}
      */
     public void find(Test test, String packageName) {
         packageName = packageName.replace('.', '/');
 
         Set<ClassLoader> set = getClassLoaders();
         for (ClassLoader classLoader : set) {
-            LOG.trace("Searching: " + classLoader);
-
             find(test, packageName, classLoader);
         }
     }
 
     protected void find(Test test, String packageName, ClassLoader loader) {
-        Enumeration<URL> urls;
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Searching for: " + test + " in package: " + packageName +
+                " using classloader: " + loader);
+        }
 
         try {
+            Method mth = loader.getClass().getMethod("getBundle", new Class[] {});
+            if (mth != null) {
+                // it's osgi bundle class loader, so we need to load implementation in bundles
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Loading from osgi buindle using classloader: " + loader);
+                }
+                loadImplementationsInBundle(test, packageName, loader, mth);
+                return;
+            }
+        } catch (NoSuchMethodException e) {
+            LOG.trace("It's not an osgi bundle classloader");
+        }
+
+        Enumeration<URL> urls;
+        try {
             urls = loader.getResources(packageName);
         } catch (IOException ioe) {
             LOG.warn("Could not read package: " + packageName, ioe);
@@ -273,8 +308,9 @@
         }
 
         while (urls.hasMoreElements()) {
+            URL url = null;
             try {
-                URL url = urls.nextElement();
+                url = urls.nextElement();
 
                 String urlPath = url.getFile();
                 urlPath = URLDecoder.decode(urlPath, "UTF-8");
@@ -289,19 +325,51 @@
                     urlPath = urlPath.substring(0, urlPath.indexOf('!'));
                 }
 
-                LOG.debug("Scanning for classes in [" + urlPath + "] matching criteria: " + test);
+                if (LOG.isTraceEnabled()) {
+                    LOG.trace("Scanning for classes in [" + urlPath + "] matching criteria: " + test);
+                }
+
                 File file = new File(urlPath);
                 if (file.isDirectory()) {
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Loading from directory: " + file);
+                    }
                     loadImplementationsInDirectory(test, packageName, file);
                 } else {
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Loading from jar: " + file);
+                    }
                     loadImplementationsInJar(test, packageName, file);
                 }
             } catch (IOException ioe) {
-                LOG.warn("could not read entries", ioe);
+                LOG.warn("Could not read entries in url: " + url, ioe);
+            }
+        }
+    }
+
+    private void loadImplementationsInBundle(Test test, String packageName, ClassLoader loader, Method mth) {
+        try {
+            Bundle bundle = (Bundle)mth.invoke(loader);
+            Bundle[] bundles = bundle.getBundleContext().getBundles();
+            for (Bundle bd : bundles) {
+                if (LOG.isTraceEnabled()) {
+                    LOG.trace("Searching in bundle:" + bd);
+                }
+
+                Enumeration<URL> paths = (Enumeration<URL>)bd.findEntries("/" + packageName, "*.class", true);
+                while (paths != null && paths.hasMoreElements()) {
+                    URL path = paths.nextElement();
+                    // substring to avoid leading slashes
+                    addIfMatching(test, path.getPath().substring(1));
+                }
             }
+        } catch (Exception e) {
+            LOG.error("Could not search osgi bundles for classes matching criteria: "
+                + test + "due to an Exception: " + e.getMessage());
         }
     }
 
+
     /**
      * Finds matches in a physical directory on a filesystem. Examines all files
      * within a directory - if the File object is not a directory, and ends with
@@ -309,11 +377,11 @@
      * according to the Test. Operates recursively to find classes within a
      * folder structure matching the package structure.
      *
-     * @param test a Test used to filter the classes that are discovered
-     * @param parent the package name up to this directory in the package
-     *                hierarchy. E.g. if /classes is in the classpath and we
-     *                wish to examine files in /classes/org/apache then the
-     *                values of <i>parent</i> would be <i>org/apache</i>
+     * @param test     a Test used to filter the classes that are discovered
+     * @param parent   the package name up to this directory in the package
+     *                 hierarchy. E.g. if /classes is in the classpath and we wish to
+     *                 examine files in /classes/org/apache then the values of
+     *                 <i>parent</i> would be <i>org/apache</i>
      * @param location a File object representing a directory
      */
     private void loadImplementationsInDirectory(Test test, String parent, File location) {
@@ -325,7 +393,6 @@
             String name = file.getName();
             if (name != null) {
                 name = name.trim();
-
                 builder.append(parent).append("/").append(name);
                 String packageOrClass = parent == null ? name : builder.toString();
 
@@ -343,18 +410,17 @@
      * structure matching the package structure. If the File is not a JarFile or
      * does not exist a warning will be logged, but no error will be raised.
      *
-     * @param test a Test used to filter the classes that are discovered
-     * @param parent the parent package under which classes must be in order to
+     * @param test    a Test used to filter the classes that are discovered
+     * @param parent  the parent package under which classes must be in order to
      *                be considered
      * @param jarfile the jar file to be examined for classes
      */
     private void loadImplementationsInJar(Test test, String parent, File jarfile) {
-
-     JarInputStream jarStream = null;
+        JarInputStream jarStream = null;
         try {
-            JarEntry entry;
             jarStream = new JarInputStream(new FileInputStream(jarfile));
 
+            JarEntry entry;
             while ((entry = jarStream.getNextJarEntry()) != null) {
                 String name = entry.getName();
                 if (name != null) {
@@ -366,15 +432,9 @@
             }
         } catch (IOException ioe) {
             LOG.error("Could not search jar file '" + jarfile + "' for classes matching criteria: " + test
-                      + "due to an IOException: " + ioe.getMessage());
+                + " due to an IOException: " + ioe.getMessage(), ioe);
         } finally {
-            try {
-             if (jarStream != null)
-             jarStream.close();
-            } catch (IOException e) {
-                LOG.warn("Failed to close jar stream: " + jarfile.getPath(), e);
-            }
-        
+            ObjectHelper.close(jarStream, jarfile.getPath(), LOG);
         }
     }
 
@@ -384,7 +444,7 @@
      * supplied.
      *
      * @param test the test used to determine if the class matches
-     * @param fqn the fully qualified name of a class
+     * @param fqn  the fully qualified name of a class
      */
     protected void addIfMatching(Test test, String fqn) {
         try {
@@ -392,26 +452,31 @@
             Set<ClassLoader> set = getClassLoaders();
             boolean found = false;
             for (ClassLoader classLoader : set) {
-                LOG.trace("Checking to see if class " + externalName + " matches criteria [" + test + "]");
-
+                if (LOG.isTraceEnabled()) {
+                    LOG.trace("Testing for class " + externalName + " matches criteria [" + test + "]");
+                }
                 try {
                     Class type = classLoader.loadClass(externalName);
                     if (test.matches(type)) {
+                        if (LOG.isTraceEnabled()) {
+                            LOG.trace("Found class: " + type + " in classloader: " + classLoader);
+                        }
                         matches.add((Class<T>)type);
                     }
                     found = true;
                     break;
                 } catch (ClassNotFoundException e) {
-                    LOG.debug("Could not find class '" + fqn + "' in class loader: " + classLoader
-                              + ". Reason: " + e, e);
+                    LOG.debug("Could not find class '" + fqn + "' in classloader: " + classLoader
+                        + ". Reason: " + e, e);
                 }
             }
             if (!found) {
-                LOG.warn("Could not find class '" + fqn + "' in any class loaders: " + set);
+                LOG.warn("Could not find class '" + fqn + "' in any classloaders: " + set);
             }
         } catch (Throwable t) {
             LOG.warn("Could not examine class '" + fqn + "' due to a " + t.getClass().getName()
-                     + " with message: " + t.getMessage());
+                + " with message: " + t.getMessage(), t);
         }
     }
+
 }

Modified: activemq/camel/trunk/pom.xml
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/pom.xml?rev=666957&r1=666956&r2=666957&view=diff
==============================================================================
--- activemq/camel/trunk/pom.xml (original)
+++ activemq/camel/trunk/pom.xml Wed Jun 11 22:23:21 2008
@@ -39,6 +39,7 @@
     <activemq-version>5.1.0</activemq-version>
     <cxf-version>2.1</cxf-version>
     <felix-version>1.4.1</felix-version>
+    <felix-osgi-version>1.0.1</felix-osgi-version>
     <geronimo-spec-version>1.1</geronimo-spec-version>
     <httpcore-version>4.0-alpha6</httpcore-version>
     <jetty-version>6.1.7</jetty-version>