You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2017/02/09 14:28:57 UTC

camel git commit: CAMEL-10812: FactoryFinder: make DefaultFactoryFinder and OsgiFactoryFinder thread safe

Repository: camel
Updated Branches:
  refs/heads/master d7947a205 -> bb224ecbc


CAMEL-10812: FactoryFinder: make DefaultFactoryFinder and OsgiFactoryFinder thread safe


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/bb224ecb
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/bb224ecb
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/bb224ecb

Branch: refs/heads/master
Commit: bb224ecbc2ab40efe01caf77493844e6f7f5f56e
Parents: d7947a2
Author: lburgazzoli <lb...@gmail.com>
Authored: Thu Feb 9 15:28:24 2017 +0100
Committer: lburgazzoli <lb...@gmail.com>
Committed: Thu Feb 9 15:28:30 2017 +0100

----------------------------------------------------------------------
 .../apache/camel/impl/DefaultFactoryFinder.java | 62 ++++++++++++++++----
 .../camel/impl/DefaultFactoryFinderTest.java    |  5 +-
 .../camel/core/osgi/OsgiFactoryFinder.java      | 27 ++++-----
 3 files changed, 64 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/bb224ecb/camel-core/src/main/java/org/apache/camel/impl/DefaultFactoryFinder.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultFactoryFinder.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultFactoryFinder.java
index 009d7b5..7697cfb 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultFactoryFinder.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultFactoryFinder.java
@@ -38,7 +38,7 @@ import org.apache.camel.util.IOHelper;
  */
 public class DefaultFactoryFinder implements FactoryFinder {
 
-    protected final ConcurrentMap<String, Class<?>> classMap = new ConcurrentHashMap<String, Class<?>>();
+    private final ConcurrentMap<String, Class<?>> classMap = new ConcurrentHashMap<String, Class<?>>();
     private final ClassResolver classResolver;
     private final String path;
 
@@ -47,10 +47,12 @@ public class DefaultFactoryFinder implements FactoryFinder {
         this.path = resourcePath;
     }
 
+    @Override
     public String getResourcePath() {
         return path;
     }
 
+    @Override
     public Object newInstance(String key) throws NoFactoryAvailableException {
         try {
             return newInstance(key, null);
@@ -59,6 +61,7 @@ public class DefaultFactoryFinder implements FactoryFinder {
         }
     }
 
+    @Override
     public <T> List<T> newInstances(String key, Injector injector, Class<T> type) throws ClassNotFoundException, IOException {
         List<Class<T>> list = CastUtils.cast(findClasses(key));
         List<T> answer = new ArrayList<T>(list.size());
@@ -66,23 +69,20 @@ public class DefaultFactoryFinder implements FactoryFinder {
         return answer;
     }
 
+    @Override
     public Class<?> findClass(String key) throws ClassNotFoundException, IOException {
         return findClass(key, null);
     }
 
+    @Override
     public Class<?> findClass(String key, String propertyPrefix) throws ClassNotFoundException, IOException {
-        String prefix = propertyPrefix != null ? propertyPrefix : "";
+        final String prefix = propertyPrefix != null ? propertyPrefix : "";
+        final String classKey = prefix + key;
 
-        Class<?> clazz = classMap.get(prefix + key);
-        if (clazz == null) {
-            clazz = newInstance(doFindFactoryProperties(key), prefix);
-            if (clazz != null) {
-                classMap.put(prefix + key, clazz);
-            }
-        }
-        return clazz;
+        return addToClassMap(classKey, () -> newInstance(doFindFactoryProperties(key), prefix));
     }
 
+    @Override
     public Class<?> findClass(String key, String propertyPrefix, Class<?> clazz) throws ClassNotFoundException, IOException {
         // Just ignore clazz which is only useful for OSGiFactoryFinder
         return findClass(key, propertyPrefix);
@@ -152,4 +152,46 @@ public class DefaultFactoryFinder implements FactoryFinder {
             IOHelper.close(in, key, null);
         }
     }
+
+    /*
+     * This is a wrapper function to deal with exceptions in lambdas: the exception
+     * is wrapped by a runtime exception (WrappedRuntimeException) which we catch
+     * later on with the only purpose to re-throw the original exception.
+     */
+    protected Class<?> addToClassMap(String key, ClassSupplier mappingFunction) throws ClassNotFoundException, IOException {
+        try {
+            return classMap.computeIfAbsent(key, (String classKey) -> {
+                try {
+                    return mappingFunction.get();
+                } catch (ClassNotFoundException e) {
+                    throw new WrappedRuntimeException(e);
+                } catch (NoFactoryAvailableException e) {
+                    throw new WrappedRuntimeException(e);
+                } catch (IOException e) {
+                    throw new WrappedRuntimeException(e);
+                }
+            });
+        } catch (WrappedRuntimeException e) {
+            if (e.getCause() instanceof ClassNotFoundException) {
+                throw (ClassNotFoundException)e.getCause();
+            } else if (e.getCause() instanceof NoFactoryAvailableException) {
+                throw (NoFactoryAvailableException)e.getCause();
+            } else if (e.getCause() instanceof IOException) {
+                throw (IOException)e.getCause();
+            } else {
+                throw new RuntimeException(e.getCause());
+            }
+        }
+    }
+
+    @FunctionalInterface
+    protected interface ClassSupplier {
+        Class<?> get() throws ClassNotFoundException, IOException;
+    }
+
+    private final class WrappedRuntimeException extends RuntimeException {
+        WrappedRuntimeException(Exception e) {
+            super(e);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/bb224ecb/camel-core/src/test/java/org/apache/camel/impl/DefaultFactoryFinderTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/impl/DefaultFactoryFinderTest.java b/camel-core/src/test/java/org/apache/camel/impl/DefaultFactoryFinderTest.java
index 1d95049..2d36c77 100644
--- a/camel-core/src/test/java/org/apache/camel/impl/DefaultFactoryFinderTest.java
+++ b/camel-core/src/test/java/org/apache/camel/impl/DefaultFactoryFinderTest.java
@@ -19,8 +19,6 @@ package org.apache.camel.impl;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.net.URL;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 
 import org.apache.camel.NoFactoryAvailableException;
@@ -35,7 +33,6 @@ import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 import static org.hamcrest.Matchers.matchesPattern;
 import static org.hamcrest.core.IsCollectionContaining.hasItem;
-import static org.hamcrest.core.IsCollectionContaining.hasItems;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
@@ -158,7 +155,7 @@ public class DefaultFactoryFinderTest {
     @Test
     public void shouldFindSingleClassFromClassMap() throws ClassNotFoundException, IOException {
         final DefaultFactoryFinder factoryFinder = new DefaultFactoryFinder(null, null);
-        factoryFinder.classMap.putIfAbsent("prefixkey", TestImplA.class);
+        factoryFinder.addToClassMap("prefixkey", () -> TestImplA.class);
 
         final Class<?> clazz = factoryFinder.findClass("key", "prefix");
 

http://git-wip-us.apache.org/repos/asf/camel/blob/bb224ecb/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java
----------------------------------------------------------------------
diff --git a/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java b/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java
index b12cf71..d28f332 100644
--- a/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java
+++ b/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java
@@ -45,12 +45,10 @@ public class OsgiFactoryFinder extends DefaultFactoryFinder {
 
     @Override
     public Class<?> findClass(String key, String propertyPrefix, Class<?> checkClass) throws ClassNotFoundException, IOException {
-        if (propertyPrefix == null) {
-            propertyPrefix = "";
-        }
+        final String prefix = propertyPrefix != null ? propertyPrefix : "";
+        final String classKey = propertyPrefix + key;
 
-        Class<?> clazz = classMap.get(propertyPrefix + key);
-        if (clazz == null) {
+        return addToClassMap(classKey, () -> {
             BundleEntry entry = getResource(key, checkClass);
             if (entry != null) {
                 URL url = entry.url;
@@ -61,22 +59,19 @@ public class OsgiFactoryFinder extends DefaultFactoryFinder {
                     reader = IOHelper.buffered(in);
                     Properties properties = new Properties();
                     properties.load(reader);
-                    String className = properties.getProperty(propertyPrefix + "class");
+                    String className = properties.getProperty(prefix + "class");
                     if (className == null) {
-                        throw new IOException("Expected property is missing: " + propertyPrefix + "class");
+                        throw new IOException("Expected property is missing: " + prefix + "class");
                     }
-                    clazz = entry.bundle.loadClass(className);
-                    classMap.put(propertyPrefix + key, clazz);
+                    return entry.bundle.loadClass(className);
                 } finally {
                     IOHelper.close(reader, key, null);
                     IOHelper.close(in, key, null);
                 }
             } else {
-                throw new NoFactoryAvailableException(propertyPrefix + key);
-            }           
-        }
-
-        return clazz;
+                throw new NoFactoryAvailableException(classKey);
+            }
+        });
     }
 
     @Override
@@ -101,7 +96,7 @@ public class OsgiFactoryFinder extends DefaultFactoryFinder {
         URL url;
         for (Bundle bundle : bundles) {
             url = bundle.getEntry(getResourcePath() + name);
-            if (url != null && checkCompat(bundle, clazz)) {
+            if (url != null && checkCompatibility(bundle, clazz)) {
                 entry = new BundleEntry();
                 entry.url = url;
                 entry.bundle = bundle;
@@ -112,7 +107,7 @@ public class OsgiFactoryFinder extends DefaultFactoryFinder {
         return entry;
     }
 
-    private boolean checkCompat(Bundle bundle, Class<?> clazz) {
+    private boolean checkCompatibility(Bundle bundle, Class<?> clazz) {
         if (clazz == null) {
             return true;
         }