Repository: tomee
Updated Branches:
  refs/heads/master 5d184de4e -> dc08c8196


TOMEE-1821 workaround for broken optional CDI extensions, allow to skip them


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

Branch: refs/heads/master
Commit: dc08c8196eeedba005de897b1f8cfe6c54943fc1
Parents: 5d184de
Author: Romain manni-Bucau <[email protected]>
Authored: Wed Jun 1 11:52:11 2016 +0200
Committer: Romain manni-Bucau <[email protected]>
Committed: Wed Jun 1 11:52:11 2016 +0200

----------------------------------------------------------------------
 .../openejb/assembler/classic/Assembler.java    |   2 +-
 .../openejb/cdi/OptimizedLoaderService.java     | 127 ++++++++++++++++++-
 .../openejb/cdi/ThreadSingletonServiceImpl.java |   2 +-
 .../openejb/testing/ApplicationComposers.java   |   1 +
 4 files changed, 124 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/dc08c819/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
----------------------------------------------------------------------
diff --git 
a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
 
b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
index 9c41a05..6d33d0b 100644
--- 
a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
+++ 
b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
@@ -1691,7 +1691,7 @@ public class Assembler extends AssemblerTool implements 
org.apache.openejb.spi.A
             services.put(ScannerService.class, new CdiScanner());
             services.put(BeanArchiveService.class, new 
OpenEJBBeanInfoService());
             services.put(ELAdaptor.class, new CustomELAdapter(appContext));
-            services.put(LoaderService.class, new OptimizedLoaderService());
+            services.put(LoaderService.class, new 
OptimizedLoaderService(appContext.getProperties()));
 
             final Properties properties = new Properties();
             
properties.setProperty(org.apache.webbeans.spi.SecurityService.class.getName(), 
ManagedSecurityService.class.getName());

http://git-wip-us.apache.org/repos/asf/tomee/blob/dc08c819/container/openejb-core/src/main/java/org/apache/openejb/cdi/OptimizedLoaderService.java
----------------------------------------------------------------------
diff --git 
a/container/openejb-core/src/main/java/org/apache/openejb/cdi/OptimizedLoaderService.java
 
b/container/openejb-core/src/main/java/org/apache/openejb/cdi/OptimizedLoaderService.java
index 9051c6f..bfa5736 100644
--- 
a/container/openejb-core/src/main/java/org/apache/openejb/cdi/OptimizedLoaderService.java
+++ 
b/container/openejb-core/src/main/java/org/apache/openejb/cdi/OptimizedLoaderService.java
@@ -28,6 +28,9 @@ import org.apache.webbeans.spi.LoaderService;
 import org.apache.webbeans.spi.plugins.OpenWebBeansPlugin;
 
 import javax.enterprise.inject.spi.Extension;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.lang.reflect.Proxy;
 import java.net.URL;
 import java.util.ArrayList;
@@ -36,6 +39,7 @@ import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Properties;
 
 /**
  * @version $Rev$ $Date$
@@ -47,13 +51,18 @@ public class OptimizedLoaderService implements 
LoaderService {
     public static final ThreadLocal<Collection<String>> ADDITIONAL_EXTENSIONS 
= new ThreadLocal<Collection<String>>();
 
     private final LoaderService loaderService;
+    private final Properties config;
 
-    public OptimizedLoaderService() {
-        this(new DefaultLoaderService());
+    public OptimizedLoaderService(final Properties appConfig) {
+        this(
+                is("openejb.cdi.ignore-not-loadable-extensions", appConfig, 
SystemInstance.get().getProperties(), "false") ?
+                        new FilterableServiceLoader() : new 
DefaultLoaderService(),
+                appConfig);
     }
 
-    public OptimizedLoaderService(final LoaderService loaderService) {
+    public OptimizedLoaderService(final LoaderService loaderService, final 
Properties appConfig) {
         this.loaderService = loaderService;
+        this.config = appConfig;
     }
 
     @Override
@@ -118,11 +127,18 @@ public class OptimizedLoaderService implements 
LoaderService {
     private boolean isFiltered(final Collection<Extension> extensions, final 
Extension next) {
         final ClassLoader containerLoader = 
ParentClassLoaderFinder.Helper.get();
         final Class<? extends Extension> extClass = next.getClass();
+        final String name = extClass.getName();
+
+        final String activeKey = name + ".active";
+        final SystemInstance systemInstance = SystemInstance.get();
+        if (!is(activeKey, config, systemInstance.getProperties(), "true")) {
+            return true;
+        }
+
         if (extClass.getClassLoader() != containerLoader) {
             return false;
         }
 
-        final String name = extClass.getName();
         switch (name) {
             case "org.apache.bval.cdi.BValExtension":
                 for (final Extension e : extensions) {
@@ -136,7 +152,7 @@ public class OptimizedLoaderService implements 
LoaderService {
                 }
                 break;
             case 
"org.apache.batchee.container.cdi.BatchCDIInjectionExtension": // see 
org.apache.openejb.batchee.BatchEEServiceManager
-                return 
"true".equals(SystemInstance.get().getProperty("tomee.batchee.cdi.use-extension",
 "false"));
+                return 
"true".equals(systemInstance.getProperty("tomee.batchee.cdi.use-extension", 
"false"));
             case 
"org.apache.commons.jcs.jcache.cdi.MakeJCacheCDIInterceptorFriendly":
                 final String spi = 
"META-INF/services/javax.cache.spi.CachingProvider";
                 try {
@@ -181,7 +197,7 @@ public class OptimizedLoaderService implements 
LoaderService {
                 clazz = 
loader.loadClass("org.apache.webbeans.jsf.plugin.OpenWebBeansJsfPlugin");
                 try {
                     list.add(OpenWebBeansPlugin.class.cast(
-                        Proxy.newProxyInstance(loader, new 
Class<?>[]{OpenWebBeansPlugin.class}, new 
ClassLoaderAwareHandler(clazz.getSimpleName(), clazz.newInstance(), loader))));
+                            Proxy.newProxyInstance(loader, new 
Class<?>[]{OpenWebBeansPlugin.class}, new 
ClassLoaderAwareHandler(clazz.getSimpleName(), clazz.newInstance(), loader))));
                 } catch (final Exception e) {
                     log.error("Unable to load OpenWebBeansPlugin: 
OpenWebBeansJsfPlugin");
                 }
@@ -191,4 +207,103 @@ public class OptimizedLoaderService implements 
LoaderService {
         }
         return list;
     }
+
+    private static boolean is(final String activeKey, final Properties config, 
final Properties fallback, final String or) {
+        return Boolean.parseBoolean(config.getProperty(activeKey, 
fallback.getProperty(activeKey, or)));
+    }
+
+    private static class FilterableServiceLoader implements LoaderService {
+        private static final String SERVICE_CONFIG = "META-INF/services/" + 
Extension.class.getName();
+        private static final String FILE_ENCODING = "UTF-8";
+
+        private List<Class<?>> foundServiceClasses = new ArrayList<Class<?>>();
+        private ClassLoader loader;
+
+        private List<Extension> loadServiceImplementations() {
+            final List<Class<?>> result = resolveServiceImplementations();
+            if (result == null) {
+                return Collections.emptyList();
+            }
+            final List<Extension> foundServices = new ArrayList<>();
+            for (final Class<?> serviceClass : result) {
+                try {
+                    
foundServices.add(Extension.class.cast(serviceClass.newInstance()));
+                } catch (final NoClassDefFoundError | InstantiationException | 
IllegalAccessException e) {
+                    log.error("Ignoring a CDI Extension, cause it can't be 
instantiated (" + serviceClass + "): " + e.getMessage());
+                }
+            }
+            return foundServices;
+        }
+
+        private List<Class<?>> resolveServiceImplementations() {
+            for (final URL configFile : getConfigFileList()) {
+                loadConfiguredServices(configFile);
+            }
+            return foundServiceClasses;
+        }
+
+        private List<URL> getConfigFileList() {
+            final List<URL> serviceFiles = new ArrayList<>();
+            try {
+                final Enumeration<URL> serviceFileEnumerator = 
loader.getResources(SERVICE_CONFIG);
+                while (serviceFileEnumerator.hasMoreElements()) {
+                    serviceFiles.add(serviceFileEnumerator.nextElement());
+                }
+            } catch (final Exception e) {
+                throw new IllegalStateException("Failed to load Extension 
configured in " + SERVICE_CONFIG, e);
+            }
+            return serviceFiles;
+        }
+
+        private void loadConfiguredServices(final URL serviceFile) {
+            try (final InputStream inputStream = serviceFile.openStream()) {
+                String serviceClassName;
+                final BufferedReader bufferedReader = new BufferedReader(new 
InputStreamReader(inputStream, FILE_ENCODING));
+                while ((serviceClassName = bufferedReader.readLine()) != null) 
{
+                    serviceClassName = 
extractConfiguredServiceClassName(serviceClassName);
+                    if (!"".equals(serviceClassName)) {
+                        loadService(serviceClassName);
+                    }
+                }
+            } catch (final Exception e) {
+                throw new IllegalStateException("Failed to process 
service-config: " + serviceFile, e);
+            }
+        }
+
+        private String extractConfiguredServiceClassName(String 
currentConfigLine) {
+            int startOfComment = currentConfigLine.indexOf('#');
+            if (startOfComment > -1) {
+                currentConfigLine = currentConfigLine.substring(0, 
startOfComment);
+            }
+            return currentConfigLine.trim();
+        }
+
+        private void loadService(final String serviceClassName) {
+            final Class<Extension> serviceClass;
+            try {
+                serviceClass = (Class<Extension>) 
loader.loadClass(serviceClassName);
+                if (!foundServiceClasses.contains(serviceClass)) {
+                    foundServiceClasses.add(serviceClass);
+                }
+            } catch (final NoClassDefFoundError |ClassNotFoundException e) {
+                log.error("Ignoring " + serviceClassName + " cause it can't be 
loaded.");
+            }
+        }
+
+        @Override
+        public <T> List<T> load(final Class<T> serviceType) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public <T> List<T> load(final Class<T> serviceType, final ClassLoader 
classLoader) {
+            loader = classLoader;
+            try {
+                return (List<T>) loadServiceImplementations();
+            } finally {
+                loader = null;
+                foundServiceClasses.clear();
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/dc08c819/container/openejb-core/src/main/java/org/apache/openejb/cdi/ThreadSingletonServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/container/openejb-core/src/main/java/org/apache/openejb/cdi/ThreadSingletonServiceImpl.java
 
b/container/openejb-core/src/main/java/org/apache/openejb/cdi/ThreadSingletonServiceImpl.java
index cd47c0c..5170eba 100644
--- 
a/container/openejb-core/src/main/java/org/apache/openejb/cdi/ThreadSingletonServiceImpl.java
+++ 
b/container/openejb-core/src/main/java/org/apache/openejb/cdi/ThreadSingletonServiceImpl.java
@@ -149,7 +149,7 @@ public class ThreadSingletonServiceImpl implements 
ThreadSingletonService {
         if (!properties.containsKey(LoaderService.class.getName())) {
             final LoaderService loaderService = 
SystemInstance.get().getComponent(LoaderService.class);
             if (loaderService == null && 
!properties.containsKey(LoaderService.class.getName())) {
-                services.put(LoaderService.class, new 
OptimizedLoaderService());
+                services.put(LoaderService.class, new 
OptimizedLoaderService(appContext.getProperties()));
             } else if (loaderService != null) {
                 services.put(LoaderService.class, loaderService);
             }

http://git-wip-us.apache.org/repos/asf/tomee/blob/dc08c819/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
----------------------------------------------------------------------
diff --git 
a/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
 
b/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
index 418fbb7..4c33372 100644
--- 
a/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
+++ 
b/container/openejb-core/src/main/java/org/apache/openejb/testing/ApplicationComposers.java
@@ -1495,6 +1495,7 @@ public class ApplicationComposers {
         private final Class<? extends Extension>[] extensions;
 
         protected ExtensionAwareOptimizedLoaderService(final Class<? extends 
Extension>[] extensions) {
+            super(new Properties());
             this.extensions = extensions;
         }
 

Reply via email to