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; }
