MEECROWAVE-164 drop catalina package from our codebase

git-svn-id: https://svn.apache.org/repos/asf/openwebbeans/meecrowave/trunk@1848295 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/meecrowave-core/src/main/java/org/apache/catalina/startup/MeecrowaveContextConfig.java b/meecrowave-core/src/main/java/org/apache/catalina/startup/MeecrowaveContextConfig.java
deleted file mode 100644
index f374c87..0000000
--- a/meecrowave-core/src/main/java/org/apache/catalina/startup/MeecrowaveContextConfig.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * 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.catalina.startup;
-
-import org.apache.catalina.Context;
-import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleEvent;
-import org.apache.catalina.WebResource;
-import org.apache.meecrowave.Meecrowave;
-import org.apache.meecrowave.logging.tomcat.LogFacade;
-import org.apache.meecrowave.openwebbeans.OWBTomcatWebScannerService;
-import org.apache.meecrowave.watching.ReloadOnChangeController;
-import org.apache.tomcat.JarScanner;
-import org.apache.tomcat.util.descriptor.web.WebXml;
-import org.apache.webbeans.config.WebBeansContext;
-import org.apache.webbeans.corespi.scanner.xbean.CdiArchive;
-import org.apache.webbeans.corespi.scanner.xbean.OwbAnnotationFinder;
-import org.xml.sax.InputSource;
-
-import javax.servlet.ServletContainerInitializer;
-import javax.servlet.annotation.HandlesTypes;
-import javax.servlet.annotation.WebFilter;
-import javax.servlet.annotation.WebListener;
-import javax.servlet.annotation.WebServlet;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Modifier;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Stream;
-
-import static java.util.Collections.emptySet;
-import static java.util.Optional.ofNullable;
-
-public class MeecrowaveContextConfig extends ContextConfig {
-    private static final byte[] DEFAULT_WEB_XML = "<web-app version=\"3.1\" />".getBytes(StandardCharsets.UTF_8);
-
-    private final Meecrowave.Builder configuration;
-    private final Map<String, Collection<Class<?>>> webClasses = new HashMap<>();
-    private final boolean fixDocBase;
-    private final ServletContainerInitializer intializer;
-    private OwbAnnotationFinder finder;
-    private ReloadOnChangeController watcher;
-
-    public MeecrowaveContextConfig(final Meecrowave.Builder configuration, final boolean fixDocBase, final ServletContainerInitializer intializer) {
-        this.configuration = configuration;
-        this.fixDocBase = fixDocBase;
-        this.intializer= intializer;
-    }
-
-    @Override
-    protected void fixDocBase() throws IOException {
-        if (!fixDocBase) {
-            return;
-        }
-        super.fixDocBase();
-    }
-
-    @Override
-    protected void webConfig() {
-        if (context.getServletContext().getAttribute("meecrowave.configuration") == null) { // redeploy
-            context.getServletContext().setAttribute("meecrowave.configuration", configuration);
-            context.addServletContainerInitializer(intializer, emptySet());
-        }
-
-        if (!configuration.isTomcatScanning()) {
-            super.webConfig();
-            return;
-        }
-
-        // eagerly start CDI to scan only once and not twice (tomcat+CDI)
-        final ClassLoader loader = context.getLoader().getClassLoader(); // should already be started at that point
-        final Thread thread = Thread.currentThread();
-        final ClassLoader old = thread.getContextClassLoader();
-        thread.setContextClassLoader(loader);
-        try {
-            final OWBTomcatWebScannerService scannerService = OWBTomcatWebScannerService.class.cast(WebBeansContext.getInstance().getScannerService());
-            scannerService.setFilter(ofNullable(context.getJarScanner()).map(JarScanner::getJarScanFilter).orElse(null), context.getServletContext());
-            scannerService.setDocBase(context.getDocBase());
-            scannerService.setShared(configuration.getSharedLibraries());
-            if (configuration.getWatcherBouncing() > 0) { // note that caching should be disabled with this config in most of the times
-                watcher = new ReloadOnChangeController(context, configuration.getWatcherBouncing());
-                scannerService.setFileVisitor(f -> watcher.register(f));
-            }
-            scannerService.scan();
-            finder = scannerService.getFinder();
-            finder.link();
-            final CdiArchive archive = CdiArchive.class.cast(finder.getArchive());
-            Stream.of(WebServlet.class, WebFilter.class, WebListener.class)
-                    .forEach(marker -> finder.findAnnotatedClasses(marker).stream()
-                            .filter(c -> !Modifier.isAbstract(c.getModifiers()) && Modifier.isPublic(c.getModifiers()))
-                            .forEach(webComponent -> webClasses.computeIfAbsent(
-                                    archive.classesByUrl().entrySet().stream()
-                                            .filter(e -> e.getValue().getClassNames().contains(webComponent.getName()))
-                                            .findFirst().get().getKey(), k -> new HashSet<>())
-                                    .add(webComponent)));
-        } finally {
-            thread.setContextClassLoader(old);
-        }
-        try {
-            super.webConfig();
-        } finally {
-            webClasses.clear();
-            finder = null;
-        }
-    }
-
-    @Override
-    public void lifecycleEvent(final LifecycleEvent event) {
-        super.lifecycleEvent(event);
-        if (watcher != null && watcher.shouldRun() && Context.class.cast(event.getLifecycle()) == context) {
-            if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) {
-                watcher.start();
-            } else if (Lifecycle.BEFORE_STOP_EVENT.equals(event.getType())) {
-                watcher.close();
-            }
-        }
-    }
-
-    @Override  // just to avoid an info log pretty useless for us
-    protected InputSource getGlobalWebXmlSource() {
-        return ofNullable(super.getGlobalWebXmlSource()).orElse(new InputSource(new ByteArrayInputStream(DEFAULT_WEB_XML)));
-    }
-
-    @Override
-    protected void processAnnotationsWebResource(final WebResource webResource, final WebXml fragment,
-                                                 final boolean handlesTypesOnly,
-                                                 final Map<String, JavaClassCacheEntry> javaClassCache) {
-        if (configuration.isTomcatScanning()) {
-            webClasses.keySet().stream().filter(k -> k.endsWith("/WEB-INF/classes"))
-                    .forEach(k -> processClasses(fragment, handlesTypesOnly, javaClassCache, k));
-        }
-    }
-
-    @Override
-    protected void processAnnotationsUrl(final URL url, final WebXml fragment, final boolean handlesTypesOnly,
-                                         final Map<String, JavaClassCacheEntry> javaClassCache) { // use our finder
-        if (!configuration.isTomcatScanning()) {
-            return;
-        }
-        processClasses(fragment, handlesTypesOnly, javaClassCache, url.toExternalForm());
-    }
-
-    @Override
-    protected void processServletContainerInitializers() { // use our finder
-        if (!configuration.isTomcatScanning()) {
-            return;
-        }
-
-        try {
-            new WebappServiceLoader<ServletContainerInitializer>(context).load(ServletContainerInitializer.class).forEach(sci -> {
-                final Set<Class<?>> classes = new HashSet<>();
-                initializerClassMap.put(sci, classes);
-
-                final HandlesTypes ht;
-                try {
-                    ht = sci.getClass().getAnnotation(HandlesTypes.class);
-                } catch (final Exception | NoClassDefFoundError e) {
-                    return;
-                }
-                if (ht == null) {
-                    return;
-                }
-                Stream.of(ht.value()).forEach(t -> {
-                    if (t.isAnnotation()) {
-                        final Class<? extends Annotation> annotation = Class.class.cast(t);
-                        finder.findAnnotatedClasses(annotation).forEach(classes::add);
-                    } else if (t.isInterface()) {
-                        finder.findImplementations(t).forEach(classes::add);
-                    } else {
-                        finder.findSubclasses(t).forEach(classes::add);
-                    }
-                });
-            });
-        } catch (final IOException e) {
-            ok = false;
-        }
-    }
-
-    private void processClasses(final WebXml fragment, final boolean handlesTypesOnly,
-                                final Map<String, JavaClassCacheEntry> javaClassCache, final String key) {
-        Collection<Class<?>> classes = webClasses.remove(key);
-        if (classes == null && key.endsWith(".jar") && key.startsWith("file:")) { // xbean vs o.a.tomcat.u.scan.JarFileUrlJar
-            classes = webClasses.remove("jar:" + key + "!/");
-        }
-        if (classes != null && !classes.isEmpty()) {
-            final ClassLoader loader = context.getLoader().getClassLoader();
-            classes.forEach(c -> {
-                try (final InputStream stream = loader.getResourceAsStream(c.getName().replace('.', '/') + ".class")) {
-                    super.processAnnotationsStream(stream, fragment, handlesTypesOnly, javaClassCache);
-                } catch (final IOException e) {
-                    new LogFacade(MeecrowaveContextConfig.class.getName()).error("Can't parse " + c);
-                }
-            });
-        }
-    }
-}
diff --git a/meecrowave-core/src/main/java/org/apache/meecrowave/Meecrowave.java b/meecrowave-core/src/main/java/org/apache/meecrowave/Meecrowave.java
index d55d9bc..5467c45 100644
--- a/meecrowave-core/src/main/java/org/apache/meecrowave/Meecrowave.java
+++ b/meecrowave-core/src/main/java/org/apache/meecrowave/Meecrowave.java
@@ -97,7 +97,7 @@
 import org.apache.catalina.session.ManagerBase;
 import org.apache.catalina.session.StandardManager;
 import org.apache.catalina.startup.Catalina;
-import org.apache.catalina.startup.MeecrowaveContextConfig;
+import org.apache.meecrowave.tomcat.MeecrowaveContextConfig;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.coyote.http2.Http2Protocol;
 import org.apache.meecrowave.api.StartListening;
diff --git a/meecrowave-core/src/main/java/org/apache/meecrowave/tomcat/MeecrowaveContextConfig.java b/meecrowave-core/src/main/java/org/apache/meecrowave/tomcat/MeecrowaveContextConfig.java
new file mode 100644
index 0000000..e91ca11
--- /dev/null
+++ b/meecrowave-core/src/main/java/org/apache/meecrowave/tomcat/MeecrowaveContextConfig.java
@@ -0,0 +1,314 @@
+/*
+ * 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.meecrowave.tomcat;
+
+import static java.util.Collections.emptySet;
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toSet;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import javax.servlet.ServletContainerInitializer;
+import javax.servlet.ServletContext;
+import javax.servlet.annotation.HandlesTypes;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.annotation.WebListener;
+import javax.servlet.annotation.WebServlet;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.startup.ContextConfig;
+import org.apache.catalina.startup.WebappServiceLoader;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.meecrowave.Meecrowave;
+import org.apache.meecrowave.logging.tomcat.LogFacade;
+import org.apache.meecrowave.openwebbeans.OWBTomcatWebScannerService;
+import org.apache.meecrowave.watching.ReloadOnChangeController;
+import org.apache.tomcat.JarScanner;
+import org.apache.tomcat.util.bcel.classfile.AnnotationEntry;
+import org.apache.tomcat.util.bcel.classfile.ClassParser;
+import org.apache.tomcat.util.bcel.classfile.JavaClass;
+import org.apache.tomcat.util.descriptor.web.WebXml;
+import org.apache.tomcat.util.descriptor.web.WebXmlParser;
+import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.corespi.scanner.xbean.CdiArchive;
+import org.apache.webbeans.corespi.scanner.xbean.OwbAnnotationFinder;
+import org.xml.sax.InputSource;
+
+public class MeecrowaveContextConfig extends ContextConfig {
+    private static final Log LOG = LogFactory.getLog(ContextConfig.class);
+
+    private static final byte[] DEFAULT_WEB_XML = "<web-app version=\"3.1\" />".getBytes(StandardCharsets.UTF_8);
+
+    private final Meecrowave.Builder configuration;
+    private final Map<String, Collection<Class<?>>> webClasses = new HashMap<>();
+    private final boolean fixDocBase;
+    private final ServletContainerInitializer intializer;
+    private OwbAnnotationFinder finder;
+    private ReloadOnChangeController watcher;
+
+    public MeecrowaveContextConfig(final Meecrowave.Builder configuration, final boolean fixDocBase, final ServletContainerInitializer intializer) {
+        this.configuration = configuration;
+        this.fixDocBase = fixDocBase;
+        this.intializer= intializer;
+    }
+
+    @Override
+    protected void fixDocBase() throws IOException {
+        if (!fixDocBase) {
+            return;
+        }
+        super.fixDocBase();
+    }
+
+    @Override
+    protected void webConfig() {
+        if (context.getServletContext().getAttribute("meecrowave.configuration") == null) { // redeploy
+            context.getServletContext().setAttribute("meecrowave.configuration", configuration);
+            context.addServletContainerInitializer(intializer, emptySet());
+        }
+
+        if (!configuration.isTomcatScanning()) {
+            doWebConfig();
+            return;
+        }
+
+        // eagerly start CDI to scan only once and not twice (tomcat+CDI)
+        final ClassLoader loader = context.getLoader().getClassLoader(); // should already be started at that point
+        final Thread thread = Thread.currentThread();
+        final ClassLoader old = thread.getContextClassLoader();
+        thread.setContextClassLoader(loader);
+        try {
+            final OWBTomcatWebScannerService scannerService = OWBTomcatWebScannerService.class.cast(WebBeansContext.getInstance().getScannerService());
+            scannerService.setFilter(ofNullable(context.getJarScanner()).map(JarScanner::getJarScanFilter).orElse(null), context.getServletContext());
+            scannerService.setDocBase(context.getDocBase());
+            scannerService.setShared(configuration.getSharedLibraries());
+            if (configuration.getWatcherBouncing() > 0) { // note that caching should be disabled with this config in most of the times
+                watcher = new ReloadOnChangeController(context, configuration.getWatcherBouncing());
+                scannerService.setFileVisitor(f -> watcher.register(f));
+            }
+            scannerService.scan();
+            finder = scannerService.getFinder();
+            finder.link();
+            final CdiArchive archive = CdiArchive.class.cast(finder.getArchive());
+            Stream.of(WebServlet.class, WebFilter.class, WebListener.class)
+                    .forEach(marker -> finder.findAnnotatedClasses(marker).stream()
+                            .filter(c -> !Modifier.isAbstract(c.getModifiers()) && Modifier.isPublic(c.getModifiers()))
+                            .forEach(webComponent -> webClasses.computeIfAbsent(
+                                    archive.classesByUrl().entrySet().stream()
+                                            .filter(e -> e.getValue().getClassNames().contains(webComponent.getName()))
+                                            .findFirst().get().getKey(), k -> new HashSet<>())
+                                    .add(webComponent)));
+        } finally {
+            thread.setContextClassLoader(old);
+        }
+        try {
+            doWebConfig();
+        } finally {
+            webClasses.clear();
+            finder = null;
+        }
+    }
+
+    // webConfig of the parent
+    private void doWebConfig() {
+        final WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
+                context.getXmlValidation(), context.getXmlBlockExternal());
+
+        final Set<WebXml> defaults = new HashSet<>();
+        defaults.add(WebXml.class.cast(invokePrivate("getDefaultWebXmlFragment", WebXmlParser.class, webXmlParser)));
+
+        final Set<WebXml> tomcatWebXml = new HashSet<>();
+        tomcatWebXml.add(WebXml.class.cast(invokePrivate("getTomcatWebXmlFragment", WebXmlParser.class, webXmlParser)));
+
+        final WebXml webXml = createWebXml();
+        final InputSource contextWebXml = getContextWebXmlSource();
+        if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
+            ok = false;
+        }
+
+        final ServletContext sContext = context.getServletContext();
+        final Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser);
+        final Set<WebXml> orderedFragments = WebXml.orderWebFragments(webXml, fragments, sContext);
+        if (ok) {
+            processServletContainerInitializers();
+        }
+
+        if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
+            final ClassLoader loader = context.getLoader().getClassLoader();
+            webClasses.forEach((k, v) -> {
+                final WebXml xml = fragments.get(k);
+                if (xml == null) {
+                    return;
+                }
+                v.forEach(clazz -> {
+                    try (final InputStream stream = loader.getResourceAsStream(clazz.getName().replace('.', '/') + ".class")) {
+                        final ClassParser parser = new ClassParser(stream);
+                        final JavaClass parsed = parser.parse();
+                        final AnnotationEntry[] annotationsEntries = parsed.getAnnotationEntries();
+                        if (annotationsEntries != null) {
+                            final String className = parsed.getClassName();
+                            for (final AnnotationEntry ae : annotationsEntries) {
+                                final String type = ae.getAnnotationType();
+                                if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) {
+                                    processAnnotationWebServlet(className, ae, xml);
+                                }else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) {
+                                    processAnnotationWebFilter(className, ae, xml);
+                                }else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) {
+                                    xml.addListener(className);
+                                }
+                            }
+                        }
+                    } catch (final IOException e) {
+                        new LogFacade(MeecrowaveContextConfig.class.getName()).error("Can't parse " + clazz);
+                    }
+                });
+            });
+        }
+
+        if (!webXml.isMetadataComplete()) {
+            if (ok) {
+                ok = webXml.merge(orderedFragments);
+            }
+            webXml.merge(tomcatWebXml);
+            webXml.merge(defaults);
+            if (ok) {
+                invokePrivate("convertJsps", WebXml.class, webXml);
+            }
+            if (ok) {
+                invokePrivate("configureContext", WebXml.class, webXml);
+            }
+        } else {
+            webXml.merge(tomcatWebXml);
+            webXml.merge(defaults);
+            invokePrivate("convertJsps", WebXml.class, webXml);
+            invokePrivate("configureContext", WebXml.class, webXml);
+        }
+
+        if (context.getLogEffectiveWebXml()) {
+            LOG.info("web.xml:\n" + webXml.toXml());
+        }
+
+        if (ok) {
+            processResourceJARs(Stream.concat(orderedFragments.stream(), fragments.values().stream()).collect(toSet()));
+        }
+
+        if (ok) {
+            initializerClassMap.forEach((key, value) -> {
+                if (value.isEmpty()) {
+                    context.addServletContainerInitializer(key, null);
+                } else {
+                    context.addServletContainerInitializer(key, value);
+                }
+            });
+        }
+    }
+
+    @Override
+    public void lifecycleEvent(final LifecycleEvent event) {
+        super.lifecycleEvent(event);
+        if (watcher != null && watcher.shouldRun() && Context.class.cast(event.getLifecycle()) == context) {
+            if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) {
+                watcher.start();
+            } else if (Lifecycle.BEFORE_STOP_EVENT.equals(event.getType())) {
+                watcher.close();
+            }
+        }
+    }
+
+    @Override  // just to avoid an info log pretty useless for us
+    protected InputSource getGlobalWebXmlSource() {
+        return ofNullable(super.getGlobalWebXmlSource()).orElse(new InputSource(new ByteArrayInputStream(DEFAULT_WEB_XML)));
+    }
+
+    @Override
+    protected void processServletContainerInitializers() { // use our finder
+        if (!configuration.isTomcatScanning()) {
+            return;
+        }
+
+        try {
+            new WebappServiceLoader<ServletContainerInitializer>(context).load(ServletContainerInitializer.class).forEach(sci -> {
+                final Set<Class<?>> classes = new HashSet<>();
+                initializerClassMap.put(sci, classes);
+
+                final HandlesTypes ht;
+                try {
+                    ht = sci.getClass().getAnnotation(HandlesTypes.class);
+                } catch (final Exception | NoClassDefFoundError e) {
+                    return;
+                }
+                if (ht == null) {
+                    return;
+                }
+                Stream.of(ht.value()).forEach(t -> {
+                    if (t.isAnnotation()) {
+                        final Class<? extends Annotation> annotation = Class.class.cast(t);
+                        classes.addAll(finder.findAnnotatedClasses(annotation));
+                    } else if (t.isInterface()) {
+                        classes.addAll(finder.findImplementations(t));
+                    } else {
+                        classes.addAll(finder.findSubclasses(t));
+                    }
+                });
+            });
+        } catch (final IOException e) {
+            ok = false;
+        }
+    }
+
+    private Object invokePrivate(final String mtdName, final Class<?> paramType, final Object param) {
+        try {
+            final Method declaredMethod = ContextConfig.class.getDeclaredMethod(mtdName, paramType);
+            if (!declaredMethod.isAccessible()) {
+                declaredMethod.setAccessible(true);
+            }
+            return declaredMethod.invoke(this, param);
+        } catch (final InvocationTargetException ite) {
+            return rethrow(ite.getTargetException());
+        } catch (final Exception ex) {
+            return rethrow(ex);
+        }
+    }
+
+    private Object rethrow(final Throwable ex) {
+        if (RuntimeException.class.isInstance(ex)) {
+            throw RuntimeException.class.cast(ex);
+        }
+        if (Error.class.isInstance(ex)) {
+            throw Error.class.cast(ex);
+        }
+        throw new IllegalStateException(ex);
+    }
+}