Author: davsclaus
Date: Mon May 30 09:26:37 2011
New Revision: 1129083

URL: http://svn.apache.org/viewvc?rev=1129083&view=rev
Log:
CAMEL-4009: Using jar cache for loading type converters, which speedup when 
using uber JARs. Thanks to Arkadi for patch. I polished his patch a bit.

Modified:
    
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java
    
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/AnnotationTypeConverterLoader.java

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java?rev=1129083&r1=1129082&r2=1129083&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultPackageScanClassResolver.java
 Mon May 30 09:26:37 2011
@@ -26,10 +26,14 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLDecoder;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
@@ -41,6 +45,7 @@ import org.apache.camel.impl.scan.Compos
 import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.PackageScanFilter;
 import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -203,6 +208,15 @@ public class DefaultPackageScanClassReso
     }
 
     protected void find(PackageScanFilter test, String packageName, 
ClassLoader loader, Set<Class<?>> classes) {
+        Map<String, List<String>> jarCache = new LinkedHashMap<String, 
List<String>>();
+
+        find(test, packageName, loader, classes, jarCache);
+
+        jarCache.clear();
+    }
+
+    protected void find(PackageScanFilter test, String packageName, 
ClassLoader loader, Set<Class<?>> classes,
+                        Map<String, List<String>> jarCache) {
         if (log.isTraceEnabled()) {
             log.trace("Searching for: {} in package: {} using classloader: 
{}", 
                     new Object[]{test, packageName, 
loader.getClass().getName()});
@@ -252,7 +266,7 @@ public class DefaultPackageScanClassReso
 
                 // osgi bundles should be skipped
                 if (url.toString().startsWith("bundle:") || 
urlPath.startsWith("bundle:")) {
-                    log.trace("It's a virtual osgi bundle, skipping");
+                    log.trace("Skipping OSGi bundle: {}", url);
                     continue;
                 }
 
@@ -285,7 +299,7 @@ public class DefaultPackageScanClassReso
                         stream = new FileInputStream(file);
                     }
 
-                    loadImplementationsInJar(test, packageName, stream, 
urlPath, classes);
+                    loadImplementationsInJar(test, packageName, stream, 
urlPath, classes, jarCache);
                 }
             } catch (IOException e) {
                 // use debug logging to avoid being to noisy in logs
@@ -304,7 +318,7 @@ public class DefaultPackageScanClassReso
      * Strategy to get the resources by the given classloader.
      * <p/>
      * Notice that in WebSphere platforms there is a {@link 
WebSpherePackageScanClassResolver}
-     * to take care of WebSphere's odditiy of resource loading.
+     * to take care of WebSphere's oddity of resource loading.
      *
      * @param loader  the classloader
      * @param packageName   the packagename for the package to load
@@ -347,7 +361,7 @@ public class DefaultPackageScanClassReso
      */
     private void loadImplementationsInDirectory(PackageScanFilter test, String 
parent, File location, Set<Class<?>> classes) {
         File[] files = location.listFiles();
-        StringBuilder builder = null;
+        StringBuilder builder;
 
         for (File file : files) {
             builder = new StringBuilder(100);
@@ -376,8 +390,27 @@ public class DefaultPackageScanClassReso
      *                be considered
      * @param stream  the inputstream of the jar file to be examined for 
classes
      * @param urlPath the url of the jar file to be examined for classes
+     * @param classes to add found and matching classes
+     * @param jarCache cache for JARs to speedup loading
      */
-    private void loadImplementationsInJar(PackageScanFilter test, String 
parent, InputStream stream, String urlPath, Set<Class<?>> classes) {
+    private void loadImplementationsInJar(PackageScanFilter test, String 
parent, InputStream stream,
+                                                       String urlPath, 
Set<Class<?>> classes, Map<String, List<String>> jarCache) {
+        ObjectHelper.notNull(classes, "classes");
+        ObjectHelper.notNull(jarCache, "jarCache");
+
+        List<String> cache = jarCache.get(urlPath);
+        if (cache == null) {
+            cache = doCacheJar(stream, urlPath);
+            jarCache.put(urlPath, cache);
+            log.debug("Cached {} JAR with {} entries", urlPath, cache.size());
+        }
+
+        doLoadImplementationsInJar(test, parent, cache, classes);
+    }
+
+    private List<String> doCacheJar(InputStream stream, String urlPath) {
+        List<String> entries = new ArrayList<String>();
+
         JarInputStream jarStream = null;
         try {
             jarStream = new JarInputStream(stream);
@@ -387,17 +420,26 @@ public class DefaultPackageScanClassReso
                 String name = entry.getName();
                 if (name != null) {
                     name = name.trim();
-                    if (!entry.isDirectory() && name.startsWith(parent) && 
name.endsWith(".class")) {
-                        addIfMatching(test, name, classes);
+                    if (!entry.isDirectory() && name.endsWith(".class")) {
+                        entries.add(name);
                     }
                 }
             }
         } catch (IOException ioe) {
-            log.warn("Cannot search jar file '" + urlPath + "' for classes 
matching criteria: " + test
-                + " due to an IOException: " + ioe.getMessage(), ioe);
+            log.warn("Cannot search jar file '" + urlPath + " due to an 
IOException: " + ioe.getMessage(), ioe);
         } finally {
             IOHelper.close(jarStream, urlPath, log);
         }
+
+        return entries;
+    }
+
+    private void doLoadImplementationsInJar(PackageScanFilter test, String 
parent, List<String> entries, Set<Class<?>> classes) {
+        for (String entry : entries) {
+            if (entry.startsWith(parent)) {
+                addIfMatching(test, entry, classes);
+            }
+        }
     }
 
     /**
@@ -414,7 +456,9 @@ public class DefaultPackageScanClassReso
             Set<ClassLoader> set = getClassLoaders();
             boolean found = false;
             for (ClassLoader classLoader : set) {
-                log.trace("Testing for class {} matches criteria [{}] using 
classloader: {}", new Object[]{externalName, test, classLoader});
+                if (log.isTraceEnabled()) {
+                    log.trace("Testing for class {} matches criteria [{}] 
using classloader: {}", new Object[]{externalName, test, classLoader});
+                }
                 try {
                     Class<?> type = classLoader.loadClass(externalName);
                     log.trace("Loaded the class: {} in classloader: {}", type, 
classLoader);

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/AnnotationTypeConverterLoader.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/AnnotationTypeConverterLoader.java?rev=1129083&r1=1129082&r2=1129083&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/AnnotationTypeConverterLoader.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/AnnotationTypeConverterLoader.java
 Mon May 30 09:26:37 2011
@@ -63,6 +63,8 @@ public class AnnotationTypeConverterLoad
 
     public void load(TypeConverterRegistry registry) throws 
TypeConverterLoaderException {
         String[] packageNames;
+
+        LOG.trace("Searching for {} services", META_INF_SERVICES);
         try {
             packageNames = findPackageNames();
             if (packageNames == null || packageNames.length == 0) {
@@ -82,6 +84,7 @@ public class AnnotationTypeConverterLoad
             return;
         }
 
+        LOG.trace("Found converter packages to scan: {}", packageNames);
         Set<Class<?>> classes = resolver.findAnnotated(Converter.class, 
packageNames);
         if (classes == null || classes.isEmpty()) {
             throw new TypeConverterLoaderException("Cannot find any type 
converter classes from the following packages: " + Arrays.asList(packageNames));
@@ -126,7 +129,7 @@ public class AnnotationTypeConverterLoad
             if (!visitedURIs.contains(path)) {
                 // remember we have visited this uri so we wont read it twice
                 visitedURIs.add(path);
-                LOG.info("Loading file {} to retrieve list of packages, from 
url: {}", META_INF_SERVICES, url);
+                LOG.debug("Loading file {} to retrieve list of packages, from 
url: {}", META_INF_SERVICES, url);
                 BufferedReader reader = new BufferedReader(new 
InputStreamReader(url.openStream()));
                 try {
                     while (true) {


Reply via email to