Author: rmannibucau Date: Tue Oct 8 15:54:55 2013 New Revision: 1530319 URL: http://svn.apache.org/r1530319 Log: TOMEE-1053 @HandlesTypes support
Added: tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/ tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/API.java tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/HandleTypesTest.java tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Impl.java tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Init.java Modified: tomee/tomee/trunk/arquillian/arquillian-tomee-remote/pom.xml tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/config/FinderFactory.java tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/OpenEJBContextConfig.java tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/EmbeddedJarScanner.java Modified: tomee/tomee/trunk/arquillian/arquillian-tomee-remote/pom.xml URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/arquillian/arquillian-tomee-remote/pom.xml?rev=1530319&r1=1530318&r2=1530319&view=diff ============================================================================== --- tomee/tomee/trunk/arquillian/arquillian-tomee-remote/pom.xml (original) +++ tomee/tomee/trunk/arquillian/arquillian-tomee-remote/pom.xml Tue Oct 8 15:54:55 2013 @@ -104,6 +104,25 @@ </dependency> <dependency> + <groupId>org.apache.openejb</groupId> + <artifactId>tomee-loader</artifactId> + <version>1.6.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.openejb</groupId> + <artifactId>tomee-catalina</artifactId> + <version>1.6.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.xbean</groupId> + <artifactId>xbean-finder-shaded</artifactId> + <version>3.14</version> + <scope>provided</scope> + </dependency> + + <dependency> <groupId>org.apache.geronimo.specs</groupId> <artifactId>geronimo-j2ee-deployment_1.1_spec</artifactId> <version>1.1</version> Added: tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/API.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/API.java?rev=1530319&view=auto ============================================================================== --- tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/API.java (added) +++ tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/API.java Tue Oct 8 15:54:55 2013 @@ -0,0 +1,20 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.openejb.arquillian.handletypes; + +public interface API { +} Added: tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/HandleTypesTest.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/HandleTypesTest.java?rev=1530319&view=auto ============================================================================== --- tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/HandleTypesTest.java (added) +++ tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/HandleTypesTest.java Tue Oct 8 15:54:55 2013 @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.openejb.arquillian.handletypes; + +import org.apache.openejb.arquillian.common.IO; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.servlet.ServletContainerInitializer; +import java.io.IOException; +import java.net.URL; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; + +@RunWith(Arquillian.class) +public class HandleTypesTest { + @Deployment(testable = false) + public static Archive<?> war() { + return ShrinkWrap.create(WebArchive.class, "ht.war") + .addClasses(API.class, Impl.class, Init.class) + .addAsServiceProvider(ServletContainerInitializer.class, Init.class); + } + + @ArquillianResource + private URL url; + + @Test + public void check() throws IOException { + final String content = IO.slurp(new URL(url.toExternalForm() + "list")); + assertThat(content, containsString(Impl.class.getName())); + } +} Added: tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Impl.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Impl.java?rev=1530319&view=auto ============================================================================== --- tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Impl.java (added) +++ tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Impl.java Tue Oct 8 15:54:55 2013 @@ -0,0 +1,20 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.openejb.arquillian.handletypes; + +public class Impl implements API { +} Added: tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Init.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Init.java?rev=1530319&view=auto ============================================================================== --- tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Init.java (added) +++ tomee/tomee/trunk/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/handletypes/Init.java Tue Oct 8 15:54:55 2013 @@ -0,0 +1,73 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.openejb.arquillian.handletypes; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContainerInitializer; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.HandlesTypes; +import java.io.IOException; +import java.util.Set; + +@HandlesTypes(API.class) +public class Init implements ServletContainerInitializer { + @Override + public void onStartup(final Set<Class<?>> classes, final ServletContext servletContext) throws ServletException { + servletContext.addServlet("list", new ListServlet(classes)).addMapping("/list"); + } + + private static class ListServlet implements Servlet { + private final Set<Class<?>> list; + + public ListServlet(final Set<Class<?>> classes) { + this.list = classes; + } + + @Override + public void init(final ServletConfig servletConfig) throws ServletException { + + } + + @Override + public ServletConfig getServletConfig() { + return null; + } + + @Override + public void service(final ServletRequest servletRequest, final ServletResponse servletResponse) throws ServletException, IOException { + if (list == null) { + servletResponse.getWriter().write("oops"); + } else { + servletResponse.getWriter().write(list.toString()); + } + } + + @Override + public String getServletInfo() { + return null; + } + + @Override + public void destroy() { + + } + } +} Modified: tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/config/FinderFactory.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/config/FinderFactory.java?rev=1530319&r1=1530318&r2=1530319&view=diff ============================================================================== --- tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/config/FinderFactory.java (original) +++ tomee/tomee/trunk/container/openejb-core/src/main/java/org/apache/openejb/config/FinderFactory.java Tue Oct 8 15:54:55 2013 @@ -135,14 +135,23 @@ public class FinderFactory { annotationFinder.enableMetaAnnotations(); } if (enableFindSubclasses()) { - annotationFinder.enableFindSubclasses(); + annotationFinder.link(); // for @HandleTypes we need interface impl, impl of abstract classes too } return annotationFinder; } - public static boolean enableFindSubclasses() { - return isJaxRsInstalled() && SystemInstance.get().getOptions().get(TOMEE_JAXRS_DEPLOY_UNDECLARED_PROP, false); + private static boolean enableFindSubclasses() { + return isTomEE() || (isJaxRsInstalled() && SystemInstance.get().getOptions().get(TOMEE_JAXRS_DEPLOY_UNDECLARED_PROP, false)); + } + + private static boolean isTomEE() { + try { + FinderFactory.class.getClassLoader().loadClass("org.apache.tomee.catalina.ServerListener"); + return true; + } catch (Throwable e) { + return false; + } } public static boolean isJaxRsInstalled() { Modified: tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/OpenEJBContextConfig.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/OpenEJBContextConfig.java?rev=1530319&r1=1530318&r2=1530319&view=diff ============================================================================== --- tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/OpenEJBContextConfig.java (original) +++ tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/OpenEJBContextConfig.java Tue Oct 8 15:54:55 2013 @@ -57,6 +57,7 @@ import org.apache.tomee.catalina.realm.T import org.apache.tomee.common.NamingUtil; import org.apache.tomee.common.ResourceFactory; import org.apache.tomee.loader.TomcatHelper; +import org.apache.xbean.finder.IAnnotationFinder; import javax.servlet.ServletContainerInitializer; import javax.servlet.http.HttpServlet; @@ -66,6 +67,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.lang.annotation.Annotation; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; @@ -88,6 +90,8 @@ public class OpenEJBContextConfig extend private static final File BASE = SystemInstance.get().getBase().getDirectory(); private TomcatWebAppBuilder.StandardContextInfo info; + private IAnnotationFinder finder = null; + private ClassLoader tempLoader = null; // processAnnotationXXX is called for each folder of WEB-INF // since we store all classes in WEB-INF we will do it only once so use this boolean to avoid multiple processing @@ -98,6 +102,11 @@ public class OpenEJBContextConfig extend info = standardContextInfo; } + public void finder(final IAnnotationFinder finder, final ClassLoader tmpLoader) { + this.finder = finder; + this.tempLoader = tmpLoader; + } + @Override public void configureStart() { super.configureStart(); @@ -373,6 +382,10 @@ public class OpenEJBContextConfig extend } catch (final NoClassDefFoundError error) { // no-op } + + // let it be GC-ed + finder = null; + tempLoader = null; } private Set<Class<?>> getJsfClasses(final Context context) { @@ -431,7 +444,7 @@ public class OpenEJBContextConfig extend return; } - internalProcessAnnotations(file, webAppInfo, fragment, handlesTypesOnly); + internalProcessAnnotations(file, webAppInfo, fragment); } @Override @@ -479,25 +492,65 @@ public class OpenEJBContextConfig extend } } - internalProcessAnnotations(currentUrlAsFile, webAppInfo, fragment, handlesTypeOnly); + internalProcessAnnotations(currentUrlAsFile, webAppInfo, fragment); } - private void internalProcessAnnotations(final File currentUrlAsFile, final WebAppInfo webAppInfo, final WebXml fragment, final boolean handlesTypeOnly) { + private void internalProcessAnnotations(final File currentUrlAsFile, final WebAppInfo webAppInfo, final WebXml fragment) { + if (typeInitializerMap.size() > 0 && finder != null) { + final ClassLoader loader = context.getLoader().getClassLoader(); + if (handlesTypesNonAnnotations) { + for (final Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry : typeInitializerMap.entrySet()) { + for (final ServletContainerInitializer sci : entry.getValue()) { + try { // we need to load the class (entry.getKey()) with the finder classloader = tempClassLoader otherwise isAssignable is false in almost all cases + final Class<?> reloadedClass = tempLoader.loadClass(entry.getKey().getName()); + final List<Class<?>> implementations = List.class.cast(finder.findImplementations(reloadedClass)); + addClassesWithRightLoader(loader, sci, implementations); + } catch (final Throwable th) { + // no-op + } + } + } + } + + if (handlesTypesAnnotations) { + for (final Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry : typeInitializerMap.entrySet()) { + final Class<?> annotation = entry.getKey(); + if (annotation.isAnnotation()) { + for (final ServletContainerInitializer sci : entry.getValue()) { + try { + final Class<? extends Annotation> reloadedAnnotation = Class.class.cast(tempLoader.loadClass(annotation.getName())); + addClassesWithRightLoader(loader, sci, finder.findAnnotatedClasses(reloadedAnnotation)); + } catch (final Throwable th) { + // no-op + } + } + } + } + } + } + for (final ClassListInfo webAnnotated : webAppInfo.webAnnotatedClasses) { try { if (!isIncludedIn(webAnnotated.name, currentUrlAsFile)) { continue; } - internalProcessAnnotationsStream(webAnnotated.list, fragment, handlesTypeOnly); - } catch (MalformedURLException e) { + internalProcessAnnotationsStream(webAnnotated.list, fragment, false); + } catch (final MalformedURLException e) { throw new IllegalArgumentException(e); } } } + private void addClassesWithRightLoader(final ClassLoader loader, final ServletContainerInitializer sci, final List<Class<?>> implementations) throws ClassNotFoundException { + final Set<Class<?>> classes = initializerClassMap.get(sci); + for (final Class<?> c : implementations) { + classes.add(loader.loadClass(c.getName())); + } + } + private void internalProcessAnnotationsStream(final Collection<String> urls, final WebXml fragment, final boolean handlesTypeOnly) { - for (String url : urls) { + for (final String url : urls) { InputStream is = null; try { is = new URL(url).openStream(); Modified: tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java?rev=1530319&r1=1530318&r2=1530319&view=diff ============================================================================== --- tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java (original) +++ tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java Tue Oct 8 15:54:55 2013 @@ -87,11 +87,7 @@ import org.apache.openejb.assembler.clas import org.apache.openejb.assembler.classic.event.NewEjbAvailableAfterApplicationCreated; import org.apache.openejb.cdi.CdiBuilder; import org.apache.openejb.cdi.OpenEJBLifecycle; -import org.apache.openejb.config.AppModule; -import org.apache.openejb.config.ConfigurationFactory; -import org.apache.openejb.config.DeploymentLoader; -import org.apache.openejb.config.TldScanner; -import org.apache.openejb.config.WebModule; +import org.apache.openejb.config.*; import org.apache.openejb.config.sys.Resource; import org.apache.openejb.core.CoreContainerSystem; import org.apache.openejb.core.ParentClassLoaderFinder; @@ -161,6 +157,7 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import static org.apache.tomee.catalina.BackportUtil.getNamingContextListener; +import static org.apache.tomee.catalina.Contexts.warPath; /** * Web application builder. @@ -1141,6 +1138,23 @@ public class TomcatWebAppBuilder impleme } } + OpenEJBContextConfig openEJBContextConfig = null; + for (final LifecycleListener listener : standardContext.findLifecycleListeners()) { + if (OpenEJBContextConfig.class.isInstance(listener)) { + openEJBContextConfig = OpenEJBContextConfig.class.cast(listener); + break; + } + } + if (openEJBContextConfig != null) { + for (final EjbModule ejbModule : appModule.getEjbModules()) { + if (ejbModule.getFile() != null && warPath(standardContext).equals(rootPath(ejbModule.getFile()))) { + openEJBContextConfig.finder(ejbModule.getFinder(), ejbModule.getClassLoader()); + break; + } + } + } + + appContext = a.createApplication(contextInfo.appInfo, classLoader); // todo add watched resources to context @@ -1299,6 +1313,13 @@ public class TomcatWebAppBuilder impleme } } + private static File rootPath(final File file) { + if (file.isDirectory() && file.getName().equals("classes") && file.getParentFile() != null && file.getParentFile().getName().equals("WEB-INF")) { + return file.getParentFile().getParentFile(); + } + return file; + } + private static void deployWebServicesIfEjbCreatedHere(final AppInfo info, final Collection<BeanContext> beanContexts) { if (beanContexts == null || beanContexts.isEmpty()) { return; Modified: tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/EmbeddedJarScanner.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/EmbeddedJarScanner.java?rev=1530319&r1=1530318&r2=1530319&view=diff ============================================================================== --- tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/EmbeddedJarScanner.java (original) +++ tomee/tomee/trunk/tomee/tomee-loader/src/main/java/org/apache/tomee/loader/EmbeddedJarScanner.java Tue Oct 8 15:54:55 2013 @@ -16,16 +16,16 @@ */ package org.apache.tomee.loader; +import org.apache.catalina.deploy.WebXml; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.openejb.config.NewLoaderLogic; import org.apache.openejb.util.URLs; +import org.apache.openejb.util.reflection.Reflections; import org.apache.tomcat.JarScanner; import org.apache.tomcat.JarScannerCallback; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.util.scan.Constants; -import org.apache.xbean.finder.filter.Filter; -import org.apache.xbean.finder.filter.Filters; import javax.servlet.ServletContext; import java.io.File; @@ -34,6 +34,7 @@ import java.net.JarURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; +import java.util.Map; import java.util.Set; /** @@ -62,15 +63,15 @@ public class EmbeddedJarScanner implemen * defined by {@link Constants#SKIP_JARS_PROPERTY} */ @Override - public void scan(ServletContext context, ClassLoader classloader, JarScannerCallback callback, Set<String> jarsToSkip) { + public void scan(final ServletContext context, final ClassLoader classloader, final JarScannerCallback callback, final Set<String> jarsToSkip) { try { final org.apache.xbean.finder.UrlSet scan = NewLoaderLogic.applyBuiltinExcludes(new org.apache.xbean.finder.UrlSet(classloader).excludeJvm(), null); // scan = scan.exclude(".*/WEB-INF/lib/.*"); // doing it simply prevent ServletContainerInitializer to de discovered - for (URL url : scan) { - if (isWebInfClasses(url)) { + for (final URL url : scan) { + if (isWebInfClasses(url) && !"org.apache.catalina.startup.ContextConfig$FragmentJarScannerCallback".equals(callback.getClass().getName())) { // we need all fragments to let SCI working continue; } @@ -81,11 +82,11 @@ public class EmbeddedJarScanner implemen try { process(callback, url); - } catch (IOException e) { + } catch (final IOException e) { log.warn(sm.getString("jarScan.webinflibFail", url), e); } } - } catch (IOException e) { + } catch (final IOException e) { log.warn(sm.getString("jarScan.classloaderFail", new URL[]{}), e); } }