You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by re...@apache.org on 2007/05/01 13:35:27 UTC

svn commit: r534014 [2/3] - in /cocoon/trunk/tools/cocoon-maven-plugin: ./ src/ src/changes/ src/main/java/org/apache/cocoon/maven/deployer/ src/main/java/org/apache/cocoon/maven/deployer/monolithic/ src/main/java/org/apache/cocoon/maven/deployer/servl...

Added: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoader.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoader.java?view=auto&rev=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoader.java (added)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoader.java Tue May  1 04:35:26 2007
@@ -0,0 +1,128 @@
+/*
+ * 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.cocoon.maven.deployer.servlet;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandlerFactory;
+
+
+/**
+ * This class loader reverses the search order for classes.  It checks this classloader
+ * before it checks its parent.
+ *
+ * @version $Id$
+ */
+public class ShieldedClassLoader extends URLClassLoader {
+
+    /**
+     * Alternate constructor to define a parent and initial <code>URL</code>s.
+     */
+    public ShieldedClassLoader(URL[] urls, final ClassLoader parent) {
+        this(urls, parent, null);
+    }
+
+    /**
+     * Alternate constructor to define a parent, initial <code>URL</code>s,
+     * and a default <code>URLStreamHandlerFactory</code>.
+     */
+    public ShieldedClassLoader(final URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
+        super(urls, parent, factory);
+    }
+
+    protected boolean tryClassHere(String name) {
+        // don't include classes in the java or javax.servlet package
+        if ( name != null && (name.startsWith("java.") || name.startsWith("javax.servlet") ) ) {
+            return false;
+        }
+        
+        return true;
+    }
+
+    protected Class getClass(String name)
+    throws ClassNotFoundException {
+        return findClass(name);
+    }
+
+    /**
+     * Loads the class from this <code>ClassLoader</class>.  If the
+     * class does not exist in this one, we check the parent.  Please
+     * note that this is the exact opposite of the
+     * <code>ClassLoader</code> spec.  We use it to work around
+     * inconsistent class loaders from third party vendors.
+     *
+     * @param     name the name of the class
+     * @param     resolve if <code>true</code> then resolve the class
+     * @return    the resulting <code>Class</code> object
+     * @exception ClassNotFoundException if the class could not be found
+     */
+    public final Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
+        // First check if it's already loaded
+        Class clazz = findLoadedClass(name);
+
+        if (clazz == null) {
+            
+            final ClassLoader parent = getParent();
+
+            if (tryClassHere(name)) {
+                try {
+                    clazz = this.getClass(name);
+                } catch (ClassNotFoundException cnfe) {
+                    if (parent == null) {
+                        // Propagate exception
+                        throw cnfe;                        
+                    }
+                }
+            }
+            
+            if (clazz == null) {
+                if (parent == null) {
+                    throw new ClassNotFoundException(name);
+                } else {
+                    // Will throw a CFNE if not found in parent
+                    clazz = parent.loadClass(name);
+                }
+            }
+        }
+
+        if (resolve) {
+            resolveClass(clazz);
+        }
+
+        return clazz;
+    }
+
+    /**
+     * Gets a resource from this <code>ClassLoader</class>.  If the
+     * resource does not exist in this one, we check the parent.
+     * Please note that this is the exact opposite of the
+     * <code>ClassLoader</code> spec.  We use it to work around
+     * inconsistent class loaders from third party vendors.
+     *
+     * @param name of resource
+     */
+    public final URL getResource(final String name) {
+        URL resource = findResource(name);
+        ClassLoader parent = this.getParent();
+        if (resource == null && parent != null) {
+            resource = parent.getResource(name);
+        }
+
+        return resource;
+    }
+}
+

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoader.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoader.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoaderManager.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoaderManager.java?view=auto&rev=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoaderManager.java (added)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoaderManager.java Tue May  1 04:35:26 2007
@@ -0,0 +1,150 @@
+/*
+ * 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.cocoon.maven.deployer.servlet;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+
+/**
+ * This class creates a singleton instance of the shielded class loader.
+ *
+ * It can be configured through context paramters:
+ * <ul>
+ * <li><code>shielded-classloader-debug</code> Can be used to turn debug messages on.</li>
+ * </ul>
+ *
+ * @version $Id$
+ */
+public class ShieldedClassLoaderManager {
+
+
+    public static final String SHIELDED_CLASSLOADER_DEBUG = "shielded-classloader-debug";
+
+    public static final String SHIELDED_CLASSLOADER_USE_REPOSITORY = "shieled-classloader-use-repository";
+
+    public static final String WEB_INF_SHIELDED_LIB = "shielded/lib";
+
+    public static final String WEB_INF_SHIELDED_CLASSES = "shielded/classes";
+
+    protected static final String SHIELDED_LIB = "/WEB-INF/" + WEB_INF_SHIELDED_LIB;
+
+    protected static final String SHIELDED_CLASSES = "/WEB-INF/" + WEB_INF_SHIELDED_CLASSES;
+
+    protected static ClassLoader shieldedClassLoader;
+
+    /**
+     * Create the class loader.
+     * @param servletContext
+     * @return
+     * @throws ServletException
+     */
+    public static synchronized ClassLoader getClassLoader(ServletContext servletContext)
+    throws ServletException {
+        if ( shieldedClassLoader == null ) {
+            try {
+                shieldedClassLoader = createClassLoader(ShieldedClassLoaderManager.class.getClassLoader(), servletContext);
+            } catch (IOException ioe) {
+                throw new ServletException("Unable to create shielded class loader.", ioe);                
+            }
+        }
+        return shieldedClassLoader;
+    }
+
+    /**
+     * Log a debug message to the log of the servlet context.
+     * This method first checks if the init parameter "shielded-classloader-debug" has the value
+     * true before it logs.
+     * @param servletContext The servlet context.
+     * @param message        The message to log.
+     */
+    public static void logDebug(ServletContext servletContext, String message) {
+        if ( servletContext.getInitParameter(SHIELDED_CLASSLOADER_DEBUG) != null
+             && servletContext.getInitParameter(SHIELDED_CLASSLOADER_DEBUG).equalsIgnoreCase("true") ) { 
+            servletContext.log(message);
+        }
+    }
+
+    /**
+     * Create the shielded class loader.
+     */
+    protected static ClassLoader createClassLoader(ClassLoader    parent,
+                                                   ServletContext servletContext)
+    throws IOException {
+        String classesDirectory = ShieldedClassLoaderManager.SHIELDED_CLASSES;
+        String jarDirectory = ShieldedClassLoaderManager.SHIELDED_LIB;
+        if ( servletContext.getInitParameter(SHIELDED_CLASSLOADER_USE_REPOSITORY) != null ) {
+            boolean useShieldedRepository = Boolean.valueOf(servletContext.getInitParameter(SHIELDED_CLASSLOADER_USE_REPOSITORY)).booleanValue();
+            if ( !useShieldedRepository ) {
+                classesDirectory = "/WEB-INF/classes";
+                jarDirectory = "/WEB-INF/libs";
+            }
+        }
+        final List urlList = new ArrayList();
+        // add url for classes dir
+        if (servletContext.getResource(classesDirectory) != null) {
+            urlList.add(servletContext.getResource(classesDirectory));
+        }
+
+        // add url for lib dir
+        if (servletContext.getResource(jarDirectory) != null) {
+            final Set resources = servletContext.getResourcePaths(jarDirectory + '/');
+            if (resources != null) {
+                // we add all urls into a temporary list first to sort them
+                // before we add them
+                final List temporaryList = new ArrayList();
+                final Iterator iter = resources.iterator();
+                while (iter.hasNext()) {
+                    final String path = (String) iter.next();
+                    if (path.endsWith(".jar") || path.endsWith(".zip")) {
+                        temporaryList.add(servletContext.getResource(path));
+                    }
+                }
+                // let's sort before adding
+                Collections.sort(temporaryList, new UrlComparator());
+                urlList.addAll(temporaryList);
+            }
+        }
+
+        URL[] urls = (URL[]) urlList.toArray(new URL[urlList.size()]);
+
+        return new ShieldedClassLoader(urls, parent);
+    }
+
+    /**
+     * Simple comparator for comparing url objects.
+     */
+    protected final static class UrlComparator implements Comparator {
+
+        public int compare(Object o1, Object o2) {
+            if (o1 instanceof URL && o2 instanceof URL) {
+                return ((URL) o1).toExternalForm().compareTo(
+                        ((URL) o2).toExternalForm());
+            }
+            return 0;
+        }
+    }
+}

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoaderManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoaderManager.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldedClassLoaderManager.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingListener.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingListener.java?view=auto&rev=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingListener.java (added)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingListener.java Tue May  1 04:35:26 2007
@@ -0,0 +1,290 @@
+/*
+ * 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.cocoon.maven.deployer.servlet;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+/**
+ * This listener can be used as a wrapper around "real" listeners to
+ * support the shielded class loader.
+ *
+ * @version $Id$
+ */
+public class ShieldingListener
+    implements HttpSessionListener,
+               ServletContextListener,
+               HttpSessionActivationListener,
+               HttpSessionAttributeListener,
+               HttpSessionBindingListener,
+               ServletContextAttributeListener {
+
+    private static final String SERVLET_CONTEXT_CREATED = "CLC";
+
+    private static final String SERVLET_CONTEXT_DESTROYED = "CLD";
+
+    private static final String SESSION_CREATED = "SEC";
+
+    private static final String SESSION_DESTROYED = "SED";
+
+    private static final String SESSION_ACTIVATED = "SEAC";
+
+    private static final String SESSION_PASSIVATE = "SEDE";
+
+    private static final String VALUE_BOUND = "VB";
+
+    private static final String VALUE_UNBOUND = "VUB";
+
+    private static final String ATTR_REPLACED = "ARE";
+
+    private static final String ATTR_REMOVED = "ADE";
+
+    private static final String ATTR_ADDED = "AAD";
+
+    private static final String CONTEXT_ATTR_REPLACED = "CARE";
+
+    private static final String CONTEXT_ATTR_REMOVED = "CADE";
+
+    private static final String CONTEXT_ATTR_ADDED = "CAAD";
+
+    protected ClassLoader classloader;
+
+    protected List httpSessionListeners = new ArrayList();
+
+    protected List servletContextListeners = new ArrayList();
+
+    protected List httpSessionActivationListeners = new ArrayList();
+
+    protected List httpSessionBindingListeners = new ArrayList();
+
+    protected List servletContextAttributeListeners = new ArrayList();
+
+    protected List httpSessionAttributeListeners = new ArrayList();
+
+    protected void init(ServletContext context) {
+        // Get the classloader
+        try {
+            this.classloader = ShieldedClassLoaderManager.getClassLoader(context);
+        } catch (ServletException se) {
+            throw new RuntimeException("Unable to create bootstrap classloader.", se);
+        }
+
+        // Create the listeners
+        final ClassLoader old = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(this.classloader);
+            final String listenersConfig = context.getInitParameter(ShieldingListener.class.getName());
+            if ( listenersConfig != null ) {
+                final StringTokenizer st = new StringTokenizer(listenersConfig, " \t\r\n\f;,", false);
+                while ( st.hasMoreTokens() ) {
+                    final String className = st.nextToken();
+                    try {
+                        ShieldedClassLoaderManager.logDebug(context, "ShieldingListener: Loading listener class " + className);
+                        Class listenerClass = this.classloader.loadClass(className);
+                        final Object listener = listenerClass.newInstance();
+                        if ( listener instanceof HttpSessionListener ) {
+                            this.httpSessionListeners.add(listener);
+                        }
+                        if ( listener instanceof ServletContextListener ) {
+                            this.servletContextListeners.add(listener);
+                        }
+                        if ( listener instanceof HttpSessionActivationListener ) {
+                            this.httpSessionActivationListeners.add(listener);
+                        }
+                        if ( listener instanceof HttpSessionAttributeListener ) {
+                            this.httpSessionAttributeListeners.add(listener);
+                        }
+                        if ( listener instanceof HttpSessionBindingListener ) {
+                            this.httpSessionBindingListeners.add(listener);
+                        }
+                        if ( listener instanceof ServletContextAttributeListener ) {
+                            this.servletContextAttributeListeners.add(listener);
+                        }
+                    } catch (Exception e) {
+                        throw new RuntimeException("Cannot load listener " + className, e);
+                    }
+                }
+            }
+        } finally {
+            Thread.currentThread().setContextClassLoader(old);
+        }
+    }
+
+    protected void invoke(List listeners, String identifier, Object event) {
+        if ( this.classloader != null ) {
+            final ClassLoader old = Thread.currentThread().getContextClassLoader();
+            try {
+                Thread.currentThread().setContextClassLoader(this.classloader);
+                final Iterator i = listeners.iterator();
+                while ( i.hasNext() ) {
+                    final Object listener = i.next();
+                    try {
+                        if ( ShieldingListener.SERVLET_CONTEXT_CREATED.equals(identifier) ) {
+                            ((ServletContextListener)listener).contextInitialized((ServletContextEvent)event);
+                        } else if ( ShieldingListener.SERVLET_CONTEXT_DESTROYED.equals(identifier) ) {
+                            ((ServletContextListener)listener).contextDestroyed((ServletContextEvent)event);                            
+                        } else if ( ShieldingListener.SESSION_CREATED.equals(identifier) ) {
+                            ((HttpSessionListener)listener).sessionCreated((HttpSessionEvent)event);                            
+                        } else if ( ShieldingListener.SESSION_DESTROYED.equals(identifier) ) {
+                            ((HttpSessionListener)listener).sessionDestroyed((HttpSessionEvent)event);                            
+                        } else if ( ShieldingListener.VALUE_BOUND.equals(identifier) ) {
+                            ((HttpSessionBindingListener)listener).valueBound((HttpSessionBindingEvent)event);                            
+                        } else if ( ShieldingListener.VALUE_UNBOUND.equals(identifier) ) {
+                            ((HttpSessionBindingListener)listener).valueUnbound((HttpSessionBindingEvent)event);                            
+                        } else if ( ShieldingListener.ATTR_ADDED.equals(identifier) ) {
+                            ((HttpSessionAttributeListener)listener).attributeAdded((HttpSessionBindingEvent)event);                            
+                        } else if ( ShieldingListener.ATTR_REMOVED.equals(identifier) ) {
+                            ((HttpSessionAttributeListener)listener).attributeRemoved((HttpSessionBindingEvent)event);                            
+                        } else if ( ShieldingListener.ATTR_REPLACED.equals(identifier) ) {
+                            ((HttpSessionAttributeListener)listener).attributeReplaced((HttpSessionBindingEvent)event);                            
+                        } else if ( ShieldingListener.CONTEXT_ATTR_ADDED.equals(identifier) ) {
+                            ((ServletContextAttributeListener)listener).attributeAdded((ServletContextAttributeEvent)event);                            
+                        } else if ( ShieldingListener.CONTEXT_ATTR_REMOVED.equals(identifier) ) {
+                            ((ServletContextAttributeListener)listener).attributeRemoved((ServletContextAttributeEvent)event);                            
+                        } else if ( ShieldingListener.CONTEXT_ATTR_REPLACED.equals(identifier) ) {
+                            ((ServletContextAttributeListener)listener).attributeReplaced((ServletContextAttributeEvent)event);                            
+                        } else if ( ShieldingListener.SESSION_ACTIVATED.equals(identifier) ) {
+                            ((HttpSessionActivationListener)listener).sessionDidActivate((HttpSessionEvent)event);                            
+                        } else if ( ShieldingListener.SESSION_PASSIVATE.equals(identifier) ) {
+                            ((HttpSessionActivationListener)listener).sessionWillPassivate((HttpSessionEvent)event);                            
+                        }
+                    } catch (Exception e) {
+                        throw new RuntimeException("Cannot invoke listener " + listener, e);
+                    }
+                }
+            } finally {
+                Thread.currentThread().setContextClassLoader(old);
+            }
+        }
+    }
+
+    /**
+     * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
+     */
+    public void contextDestroyed(ServletContextEvent contextEvent) {
+        this.invoke(this.servletContextListeners, ShieldingListener.SERVLET_CONTEXT_DESTROYED, contextEvent);
+    }
+
+    /**
+     * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
+     */
+    public void contextInitialized(ServletContextEvent contextEvent) {
+        final ServletContext context = contextEvent.getServletContext();
+        this.init(context);
+
+        this.invoke(this.servletContextListeners, ShieldingListener.SERVLET_CONTEXT_CREATED, contextEvent);
+    }
+    
+    /**
+     * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent)
+     */
+    public void sessionCreated(HttpSessionEvent event) {
+        this.invoke(this.httpSessionListeners, ShieldingListener.SESSION_CREATED, event);
+    }
+
+    /**
+     * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
+     */
+    public void sessionDestroyed(HttpSessionEvent event) {
+        this.invoke(this.httpSessionListeners, ShieldingListener.SESSION_DESTROYED, event);
+    }
+
+    /**
+     * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)
+     */
+    public void valueBound(HttpSessionBindingEvent event) {
+        this.invoke(this.httpSessionBindingListeners, ShieldingListener.VALUE_BOUND, event);
+    }
+
+    /**
+     * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)
+     */
+    public void valueUnbound(HttpSessionBindingEvent event) {
+        this.invoke(this.httpSessionBindingListeners, ShieldingListener.VALUE_UNBOUND, event);
+    }
+
+    /**
+     * @see javax.servlet.http.HttpSessionAttributeListener#attributeAdded(javax.servlet.http.HttpSessionBindingEvent)
+     */
+    public void attributeAdded(HttpSessionBindingEvent event) {
+        this.invoke(this.httpSessionAttributeListeners, ShieldingListener.ATTR_ADDED, event);
+    }
+
+    /**
+     * @see javax.servlet.http.HttpSessionAttributeListener#attributeRemoved(javax.servlet.http.HttpSessionBindingEvent)
+     */
+    public void attributeRemoved(HttpSessionBindingEvent event) {
+        this.invoke(this.httpSessionAttributeListeners, ShieldingListener.ATTR_REMOVED, event);
+    }
+
+    /**
+     * @see javax.servlet.http.HttpSessionAttributeListener#attributeReplaced(javax.servlet.http.HttpSessionBindingEvent)
+     */
+    public void attributeReplaced(HttpSessionBindingEvent event) {
+        this.invoke(this.httpSessionAttributeListeners, ShieldingListener.ATTR_REPLACED, event);
+    }
+
+    /**
+     * @see javax.servlet.http.HttpSessionActivationListener#sessionDidActivate(javax.servlet.http.HttpSessionEvent)
+     */
+    public void sessionDidActivate(HttpSessionEvent event) {
+        this.invoke(this.httpSessionActivationListeners, ShieldingListener.SESSION_ACTIVATED, event);
+    }
+
+    /**
+     * @see javax.servlet.http.HttpSessionActivationListener#sessionWillPassivate(javax.servlet.http.HttpSessionEvent)
+     */
+    public void sessionWillPassivate(HttpSessionEvent event) {
+        this.invoke(this.httpSessionActivationListeners, ShieldingListener.SESSION_PASSIVATE, event);
+    }
+
+    /**
+     * @see javax.servlet.ServletContextAttributeListener#attributeAdded(javax.servlet.ServletContextAttributeEvent)
+     */
+    public void attributeAdded(ServletContextAttributeEvent event) {
+        this.invoke(this.servletContextAttributeListeners, ShieldingListener.CONTEXT_ATTR_ADDED, event);
+    }
+
+    /**
+     * @see javax.servlet.ServletContextAttributeListener#attributeRemoved(javax.servlet.ServletContextAttributeEvent)
+     */
+    public void attributeRemoved(ServletContextAttributeEvent event) {
+        this.invoke(this.servletContextAttributeListeners, ShieldingListener.CONTEXT_ATTR_REMOVED, event);
+    }
+
+    /**
+     * @see javax.servlet.ServletContextAttributeListener#attributeReplaced(javax.servlet.ServletContextAttributeEvent)
+     */
+    public void attributeReplaced(ServletContextAttributeEvent event) {
+        this.invoke(this.servletContextAttributeListeners, ShieldingListener.CONTEXT_ATTR_REPLACED, event);
+    }
+}
\ No newline at end of file

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingListener.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingListener.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServlet.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServlet.java?view=auto&rev=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServlet.java (added)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServlet.java Tue May  1 04:35:26 2007
@@ -0,0 +1,116 @@
+/*
+ * 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.cocoon.maven.deployer.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
+
+/**
+ * This servlet builds a classloading sandbox and runs another servlet inside
+ * that sandbox. The purpose is to shield the libraries and classes shipped with
+ * the web application from any other classes with the same name that may exist
+ * in the system, such as Xerces and Xalan versions included in JDK 1.4.
+ * <p>
+ * This servlet propagates all initialisation parameters to the sandboxed
+ * servlet, and requires the parameter <code>servlet-class</code>.
+ * <ul>
+ * <li><code>servlet-class</code> defines the sandboxed servlet class.</li>
+ * </ul>
+ *
+ * @version $Id$
+ */
+public class ShieldingServlet extends HttpServlet {
+
+    protected Servlet servlet;
+
+    protected ClassLoader classloader;
+
+    /**
+     * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
+     */
+    public void init(ServletConfig config) throws ServletException {
+        super.init(config);
+        // Get the classloader
+        this.classloader = ShieldedClassLoaderManager.getClassLoader(config.getServletContext());
+
+        String servletName = config.getInitParameter("servlet-class");
+        if (servletName == null) {
+            throw new ServletException("ShieldingServlet: Init-Parameter 'servlet-class' is missing.");
+        }
+        ShieldedClassLoaderManager.logDebug(config.getServletContext(),
+                                             "ShieldingServlet: Loading servlet class " + servletName);
+
+        // Create the servlet
+        try {
+
+            Class servletClass = this.classloader.loadClass(servletName);
+            this.servlet = (Servlet) servletClass.newInstance();
+
+        } catch (Exception e) {
+            throw new ServletException("Cannot load servlet " + servletName, e);
+        }
+
+        // Always set the context classloader. JAXP uses it to find a
+        // ParserFactory,
+        // and thus fails if it's not set to the webapp classloader.
+        final ClassLoader old = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(this.classloader);
+
+            // Inlitialize the actual servlet
+            this.servlet.init(this.getServletConfig());
+        } finally {
+            Thread.currentThread().setContextClassLoader(old);
+        }
+
+    }
+
+    /**
+     * Service the request by delegating the call to the real servlet
+     */
+    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
+        final ClassLoader old = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(this.classloader);
+            this.servlet.service(request, response);
+        } finally {
+            Thread.currentThread().setContextClassLoader(old);
+        }
+    }
+
+    /**
+     * Destroy the actual servlet
+     */
+    public void destroy() {
+        if (this.servlet != null) {
+            final ClassLoader old = Thread.currentThread().getContextClassLoader();
+            try {
+                Thread.currentThread().setContextClassLoader(this.classloader);
+                this.servlet.destroy();
+            } finally {
+                Thread.currentThread().setContextClassLoader(old);
+            }
+        }
+        super.destroy();
+    }
+}
\ No newline at end of file

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServlet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServlet.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServlet.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServletFilter.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServletFilter.java?view=auto&rev=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServletFilter.java (added)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServletFilter.java Tue May  1 04:35:26 2007
@@ -0,0 +1,106 @@
+/*
+ * 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.cocoon.maven.deployer.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+/**
+ * This filter can be used as a wrapper around a "real" filter to
+ * support the shielded class loader.
+ *
+ * @version $Id$
+ */
+public class ShieldingServletFilter implements Filter {
+
+    protected Filter filter;
+
+    protected ClassLoader classloader;
+
+    /**
+     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
+     */
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+    throws IOException, ServletException {
+        if ( this.filter != null ) {
+            final ClassLoader old = Thread.currentThread().getContextClassLoader();
+            try {
+                Thread.currentThread().setContextClassLoader(this.classloader);
+
+                this.filter.doFilter(request, response, chain);
+            } finally {
+                Thread.currentThread().setContextClassLoader(old);
+            }            
+        }
+    }
+
+    /**
+     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
+     */
+    public void init(FilterConfig config) throws ServletException {
+        // Get the classloader
+        this.classloader = ShieldedClassLoaderManager.getClassLoader(config.getServletContext());
+
+        String filterName = config.getInitParameter("filter-class");
+        if (filterName == null) {
+            throw new ServletException("ShieldingServletFilter: 'filter-class' parameter is missing.");
+        }
+        ShieldedClassLoaderManager.logDebug(config.getServletContext(),
+                                             "ShieldingServletFilter: Loading filter class " + filterName);
+        
+        // Create the filter
+        try {
+
+            Class filterClass = this.classloader.loadClass(filterName);
+            this.filter = (Filter) filterClass.newInstance();
+
+        } catch (Exception e) {
+            throw new ServletException("Cannot load filter " + filterName, e);
+        }
+
+        final ClassLoader old = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(this.classloader);
+
+            // Inlitialize the actual filter
+            this.filter.init(config);
+        } finally {
+            Thread.currentThread().setContextClassLoader(old);
+        }
+    }
+
+    /**
+     * @see javax.servlet.Filter#destroy()
+     */
+    public void destroy() {
+        if (this.filter != null) {
+            final ClassLoader old = Thread.currentThread().getContextClassLoader();
+            try {
+                Thread.currentThread().setContextClassLoader(this.classloader);
+                this.filter.destroy();
+            } finally {
+                Thread.currentThread().setContextClassLoader(old);
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServletFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServletFilter.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/servlet/ShieldingServletFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/CopyUtils.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/CopyUtils.java?view=auto&rev=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/CopyUtils.java (added)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/CopyUtils.java Tue May  1 04:35:26 2007
@@ -0,0 +1,39 @@
+/*
+ * 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.cocoon.maven.deployer.utils;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+
+/**
+ * @version $Id$
+ */
+public class CopyUtils {
+    public static void copy( InputStream is, OutputStream os ) throws IOException {
+        try {
+            IOUtils.copy(is, os);
+        } finally {
+            IOUtils.closeQuietly(is);
+            IOUtils.closeQuietly(os);
+        }
+    }
+}

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/CopyUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/CopyUtils.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/CopyUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/FileUtils.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/FileUtils.java?view=auto&rev=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/FileUtils.java (added)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/FileUtils.java Tue May  1 04:35:26 2007
@@ -0,0 +1,38 @@
+/*
+ * 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.cocoon.maven.deployer.utils;
+
+import java.io.File;
+
+/**
+ * Utitily class to handle ZIP archives.
+ * 
+ * @version $Id$
+ */
+public class FileUtils {
+	/**
+	 * Prepare directory structure for non-existing file
+	 */
+	public static File createPath(File file) {
+        if ( file.getParentFile() != null && !file.getParentFile().exists())
+            file.getParentFile().mkdirs();
+        return file;
+	}
+
+
+	
+}

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/FileUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/FileUtils.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/FileUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/WildcardHelper.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/WildcardHelper.java?view=auto&rev=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/WildcardHelper.java (added)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/WildcardHelper.java Tue May  1 04:35:26 2007
@@ -0,0 +1,383 @@
+/*
+ * 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.cocoon.maven.deployer.utils;
+
+import java.util.HashMap;
+
+/**
+ * This class is an utility class that perform wilcard-patterns matching and
+ * isolation.
+ *
+ * Copy from cocoon-core.
+ * 
+ * @version $Id$
+ */
+public class WildcardHelper {
+
+    /** The int representing '*' in the pattern <code>int []</code>. */
+    protected static final int MATCH_FILE = -1;
+    /** The int representing '**' in the pattern <code>int []</code>. */
+    protected static final int MATCH_PATH = -2;
+    /** The int representing begin in the pattern <code>int []</code>. */
+    protected static final int MATCH_BEGIN = -4;
+    /** The int representing end in pattern <code>int []</code>. */
+    protected static final int MATCH_THEEND = -5;
+    /** The int value that terminates the pattern <code>int []</code>. */
+    protected static final int MATCH_END = -3;
+
+
+    /**
+     * Translate the given <code>String</code> into a <code>int []</code>
+     * representing the pattern matchable by this class.
+     * <br>
+     * This function translates a <code>String</code> into an int array
+     * converting the special '*' and '\' characters.
+     * <br>
+     * Here is how the conversion algorithm works:
+     * <ul>
+     *   <li>The '*' character is converted to MATCH_FILE, meaning that zero
+     *        or more characters (excluding the path separator '/') are to
+     *        be matched.</li>
+     *   <li>The '**' sequence is converted to MATCH_PATH, meaning that zero
+     *       or more characters (including the path separator '/') are to
+     *        be matched.</li>
+     *   <li>The '\' character is used as an escape sequence ('\*' is
+     *       translated in '*', not in MATCH_FILE). If an exact '\' character
+     *       is to be matched the source string must contain a '\\'.
+     *       sequence.</li>
+     * </ul>
+     * When more than two '*' characters, not separated by another character,
+     * are found their value is considered as '**' (MATCH_PATH).
+     * <br>
+     * The array is always terminated by a special value (MATCH_END).
+     * <br>
+     * All MATCH* values are less than zero, while normal characters are equal
+     * or greater.
+     *
+     * @param data The string to translate.
+     * @return The encoded string as an int array, terminated by the MATCH_END
+     *         value (don't consider the array length).
+     * @exception NullPointerException If data is null.
+     */
+    public static int[] compilePattern(String data)
+    throws NullPointerException {
+
+        // Prepare the arrays
+        int expr[] = new int[data.length() + 2];
+        char buff[] = data.toCharArray();
+
+        // Prepare variables for the translation loop
+        int y = 0;
+        boolean slash = false;
+
+        // Must start from beginning
+        expr[y++] = MATCH_BEGIN;
+
+        if (buff.length > 0) {
+            if (buff[0]=='\\') {
+                slash = true;
+            } else if (buff[0] == '*') {
+                expr[y++] = MATCH_FILE;
+            }  else {
+                expr[y++] = buff[0];
+            }
+
+            // Main translation loop
+            for (int x = 1; x < buff.length; x++) {
+                // If the previous char was '\' simply copy this char.
+                if (slash) {
+                    expr[y++] = buff[x];
+                    slash = false;
+                // If the previous char was not '\' we have to do a bunch of checks
+                } else {
+                    // If this char is '\' declare that and continue
+                    if (buff[x] == '\\') {
+                        slash = true;
+                    // If this char is '*' check the previous one
+                    } else if (buff[x] == '*') {
+                        // If the previous character als was '*' match a path
+                        if (expr[y-1] <= MATCH_FILE) {
+                            expr[y-1] = MATCH_PATH;
+                        } else {
+                            expr[y++] = MATCH_FILE;
+                        }
+                    } else {
+                        expr[y++]=buff[x];
+                    }
+                }
+            }
+        }
+
+        // Must match end at the end
+        expr[y] = MATCH_THEEND;
+        return expr;
+    }
+
+    /**
+     * match a pattern agains a string and isolates wildcard replacement into a
+     * <code>Stack</code>.
+     */
+    public static boolean match (HashMap map, String data, int[] expr) 
+    throws NullPointerException {
+        if (data == null) {
+            throw new NullPointerException ("No data provided");
+        }
+        if (expr == null) {
+            throw new NullPointerException ("No pattern expression provided");
+        }
+
+
+        char buff[] = data.toCharArray();
+        // Allocate the result buffer
+        char rslt[] = new char[expr.length + buff.length];
+
+
+        // The previous and current position of the expression character
+        // (MATCH_*)
+        int charpos = 0;
+
+        // The position in the expression, input, translation and result arrays
+        int exprpos = 0;
+        int buffpos = 0;
+        int rsltpos = 0;
+        int offset = -1;
+
+        // The matching count
+        int mcount = 0;
+
+        if ( map != null ) {
+            // We want the complete data be in {0}
+            map.put(Integer.toString(mcount),data);
+        }
+
+        // First check for MATCH_BEGIN
+        boolean matchBegin = false;
+        if (expr[charpos] == MATCH_BEGIN) {
+            matchBegin = true;
+            exprpos = ++charpos;
+        }
+
+        // Search the fist expression character (except MATCH_BEGIN - already skipped)
+        while (expr[charpos] >= 0)
+            charpos++;
+
+        // The expression charater (MATCH_*)
+        int exprchr = expr[charpos];
+
+        while (true) {
+            // Check if the data in the expression array before the current
+            // expression character matches the data in the input buffer
+            if (matchBegin) {
+                if (!matchArray(expr, exprpos, charpos, buff, buffpos))
+                    return (false);
+                matchBegin = false;
+            } else {
+                offset = indexOfArray (expr, exprpos, charpos, buff,
+                        buffpos);
+                if (offset < 0)
+                    return (false);
+            }
+
+            // Check for MATCH_BEGIN
+            if (matchBegin) {
+                if (offset != 0)
+                    return (false);
+                matchBegin = false;
+            }
+
+            // Advance buffpos
+            buffpos += (charpos - exprpos);
+
+            // Check for END's
+            if (exprchr == MATCH_END) {
+                if (rsltpos > 0 && map != null) {
+                    map.put(Integer.toString(++mcount),new String(rslt, 0, rsltpos));
+                }
+                // Don't care about rest of input buffer
+                return (true);
+            } else if (exprchr == MATCH_THEEND) {
+                if (rsltpos > 0 && map != null ) {
+                    map.put (Integer.toString(++mcount),new String(rslt, 0, rsltpos));
+                }
+                // Check that we reach buffer's end
+                return (buffpos == buff.length);
+            }
+
+            // Search the next expression character
+            exprpos = ++charpos;
+            while (expr[charpos] >= 0)
+                charpos++;
+            int prevchr = exprchr;
+            exprchr = expr[charpos];
+
+            // We have here prevchr == * or **.
+            offset = (prevchr == MATCH_FILE) ?
+                    indexOfArray (expr, exprpos, charpos, buff, buffpos) :
+                    lastIndexOfArray (expr, exprpos, charpos, buff,
+                    buffpos);
+
+            if (offset < 0)
+                return (false);
+
+            // Copy the data from the source buffer into the result buffer
+            // to substitute the expression character
+            if (prevchr == MATCH_PATH) {
+                while (buffpos < offset)
+                    rslt[rsltpos++] = buff[buffpos++];
+            } else {
+                // Matching file, don't copy '/'
+                while (buffpos < offset) {
+                    if (buff[buffpos] == '/')
+                        return (false);
+                    rslt[rsltpos++] = buff[buffpos++];
+                }
+            }
+
+            if ( map != null ) {
+                map.put(Integer.toString(++mcount),new String (rslt, 0, rsltpos));
+            }
+            rsltpos = 0;
+        }
+    }
+
+    /**
+      * Get the offset of a part of an int array within a char array.
+      * <br>
+      * This method return the index in d of the first occurrence after dpos of
+      * that part of array specified by r, starting at rpos and terminating at
+      * rend.
+      *
+      * @param r The array containing the data that need to be matched in d.
+      * @param rpos The index of the first character in r to look for.
+      * @param rend The index of the last character in r to look for plus 1.
+      * @param d The array of char that should contain a part of r.
+      * @param dpos The starting offset in d for the matching.
+      * @return The offset in d of the part of r matched in d or -1 if that was
+      *         not found.
+      */
+    protected static int indexOfArray (int r[], int rpos, int rend,
+            char d[], int dpos) {
+        // Check if pos and len are legal
+        if (rend < rpos)
+            throw new IllegalArgumentException ("rend < rpos");
+        // If we need to match a zero length string return current dpos
+        if (rend == rpos)
+            return (d.length); //?? dpos?
+        // If we need to match a 1 char length string do it simply
+        if ((rend - rpos) == 1) {
+            // Search for the specified character
+            for (int x = dpos; x < d.length; x++)
+                if (r[rpos] == d[x])
+                    return (x);
+        }
+        // Main string matching loop. It gets executed if the characters to
+        // match are less then the characters left in the d buffer
+        while ((dpos + rend - rpos) <= d.length) {
+            // Set current startpoint in d
+            int y = dpos;
+            // Check every character in d for equity. If the string is matched
+            // return dpos
+            for (int x = rpos; x <= rend; x++) {
+                if (x == rend)
+                    return (dpos);
+                if (r[x] != d[y++])
+                    break;
+            }
+            // Increase dpos to search for the same string at next offset
+            dpos++;
+        }
+        // The remaining chars in d buffer were not enough or the string
+        // wasn't matched
+        return (-1);
+    }
+
+    /**
+      * Get the offset of a last occurance of an int array within a char array.
+      * <br>
+      * This method return the index in d of the last occurrence after dpos of
+      * that part of array specified by r, starting at rpos and terminating at
+      * rend.
+      *
+      * @param r The array containing the data that need to be matched in d.
+      * @param rpos The index of the first character in r to look for.
+      * @param rend The index of the last character in r to look for plus 1.
+      * @param d The array of char that should contain a part of r.
+      * @param dpos The starting offset in d for the matching.
+      * @return The offset in d of the last part of r matched in d or -1 if that was
+      *         not found.
+      */
+    protected static int lastIndexOfArray (int r[], int rpos, int rend,
+            char d[], int dpos) {
+        // Check if pos and len are legal
+        if (rend < rpos)
+            throw new IllegalArgumentException ("rend < rpos");
+        // If we need to match a zero length string return current dpos
+        if (rend == rpos)
+            return (d.length); //?? dpos?
+
+        // If we need to match a 1 char length string do it simply
+        if ((rend - rpos) == 1) {
+            // Search for the specified character
+            for (int x = d.length - 1; x > dpos; x--)
+                if (r[rpos] == d[x])
+                    return (x);
+        }
+
+        // Main string matching loop. It gets executed if the characters to
+        // match are less then the characters left in the d buffer
+        int l = d.length - (rend - rpos);
+        while (l >= dpos) {
+            // Set current startpoint in d
+            int y = l;
+            // Check every character in d for equity. If the string is matched
+            // return dpos
+            for (int x = rpos; x <= rend; x++) {
+                if (x == rend)
+                    return (l);
+                if (r[x] != d[y++])
+                    break;
+            }
+            // Decrease l to search for the same string at next offset
+            l--;
+        }
+        // The remaining chars in d buffer were not enough or the string
+        // wasn't matched
+        return (-1);
+    }
+
+    /**
+      * Matches elements of array r from rpos to rend with array d, starting from dpos.
+      * <br>
+      * This method return true if elements of array r from rpos to rend
+      * equals elements of array d starting from dpos to dpos+(rend-rpos).
+      *
+      * @param r The array containing the data that need to be matched in d.
+      * @param rpos The index of the first character in r to look for.
+      * @param d The array of char that should start from a part of r.
+      * @param dpos The starting offset in d for the matching.
+      * @return true if array d starts from portion of array r.
+      */
+    protected static boolean matchArray (int r[], int rpos, int rend,
+            char d[], int dpos) {
+        if (d.length - dpos < rend - rpos)
+            return (false);
+        for (int i = rpos; i < rend; i++)
+            if (r[i] != d[dpos++])
+                return (false);
+        return (true);
+    }
+}

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/WildcardHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/WildcardHelper.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/WildcardHelper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/XMLUtils.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/XMLUtils.java?view=auto&rev=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/XMLUtils.java (added)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/XMLUtils.java Tue May  1 04:35:26 2007
@@ -0,0 +1,147 @@
+/*
+ * 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.cocoon.maven.deployer.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * @version $Id$
+ */
+public class XMLUtils {
+
+    public static Document parseXml(InputStream source) throws IOException, SAXException {
+        try {
+            DocumentBuilderFactory documentFactory = DocumentBuilderFactory.newInstance();
+            documentFactory.setNamespaceAware(true);
+            documentFactory.setValidating(false);
+            DocumentBuilder docBuilder = documentFactory.newDocumentBuilder();
+            // Parse using the local dtds instead of remote dtds. This
+            // allows to deploy the application offline
+            docBuilder.setEntityResolver(new EntityResolver() {
+                public InputSource resolveEntity(String publicId, String systemId) throws SAXException,
+                        java.io.IOException {
+                    if (systemId.equals("http://java.sun.com/dtd/web-app_2_3.dtd")) {
+                        return new InputSource(getClass().getResourceAsStream("web-app_2_3.dtd"));
+                    }
+                    return null;
+                }
+            });
+
+            return docBuilder.parse(source);
+        } catch (ParserConfigurationException pce) {
+            throw new IOException("Creating document failed:" + pce.getMessage());
+        }
+    }
+
+    public static void write(Document node, OutputStream out) throws TransformerFactoryConfigurationError, TransformerException {
+        final Properties format = new Properties();
+        format.put(OutputKeys.METHOD, "xml");
+        format.put(OutputKeys.OMIT_XML_DECLARATION, "no");
+        format.put(OutputKeys.INDENT, "yes");
+        if (node.getDoctype() != null) {
+            if (node.getDoctype().getPublicId() != null) {
+                format.put(OutputKeys.DOCTYPE_PUBLIC, node.getDoctype().getPublicId());
+            }
+            if (node.getDoctype().getSystemId() != null) {
+                format.put(OutputKeys.DOCTYPE_SYSTEM, node.getDoctype().getSystemId());
+            }
+        }
+        Transformer transformer;
+        transformer = TransformerFactory.newInstance().newTransformer();
+        transformer.setOutputProperties(format);
+        transformer.transform(new DOMSource(node), new StreamResult(out));
+    }
+
+    public static List getChildNodes(Element parent, String nodeName) {
+        final List nodes = new ArrayList();
+        if (parent != null && nodeName != null) {
+            final NodeList children = parent.getChildNodes();
+            if (children != null) {
+                for (int i = 0; i < children.getLength(); i++) {
+                    if (nodeName.equals(children.item(i).getLocalName())) {
+                        nodes.add(children.item(i));
+                    }
+                }
+            }
+        }
+        return nodes;
+    }
+
+    public static Element getChildNode(Element parent, String nodeName) {
+        final List children = getChildNodes(parent, nodeName);
+        if (children.size() > 0) {
+            return (Element) children.get(0);
+        }
+
+        return null;
+    }
+
+    public static String getValue(Element node) {
+        if (node != null) {
+            if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
+                return node.getNodeValue();
+            } else {
+                node.normalize();
+                NodeList childs = node.getChildNodes();
+                int i = 0;
+                int length = childs.getLength();
+                while (i < length) {
+                    if (childs.item(i).getNodeType() == Node.TEXT_NODE) {
+                        return childs.item(i).getNodeValue().trim();
+                    } else {
+                        i++;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public static void setValue(Element node, String value) {
+        if (node != null) {
+            // remove all children
+            while (node.hasChildNodes()) {
+                node.removeChild(node.getFirstChild());
+            }
+            node.appendChild(node.getOwnerDocument().createTextNode(value));
+        }
+    }
+}
\ No newline at end of file

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/XMLUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/XMLUtils.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/deployer/utils/XMLUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/rcl/ReloadingWebappMojo.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/rcl/ReloadingWebappMojo.java?view=diff&rev=534014&r1=533959&r2=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/rcl/ReloadingWebappMojo.java (original)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/rcl/ReloadingWebappMojo.java Tue May  1 04:35:26 2007
@@ -23,9 +23,12 @@
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
+import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -36,6 +39,7 @@
 import java.util.Set;
 
 import org.antlr.stringtemplate.StringTemplate;
+import org.apache.cocoon.maven.deployer.AbstractDeployMojo;
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
@@ -56,7 +60,7 @@
 import org.apache.maven.project.artifact.MavenMetadataSource;
 
 /**
- * @goal webapp
+ * @goal rcl
  * @requiresProject true
  * @requiresDependencyResolution runtime
  * @execute phase="process-classes"
@@ -210,7 +214,10 @@
         createSpringProperties(webAppBaseDir, props);
         
         // based on the RCL configuration file, create a Cocoon properties file
-        createCocoonProperties(webAppBaseDir, props);        
+        createCocoonProperties(webAppBaseDir, props);
+        
+        // apply xpatch files
+        applyXpatchFiles(webAppBaseDir, props);
 
     }
 
@@ -318,6 +325,36 @@
         log4jTemplateMap.put("useSocketAppender", new Boolean(this.useSocketAppender));
         writeStringTemplateToFile(webAppBaseDir, WEB_INF_LOG4J, customLog4jXconf, log4jTemplateMap);
     }
+    
+
+    private void applyXpatchFiles(File webAppBaseDir, RwmProperties props) throws MojoExecutionException {
+        // find all xpatch files in all configured blocks
+        Set classesDirs = props.getClassesDirs();
+        File[] allXPatchFiles = new File[0];
+        for(Iterator it = classesDirs.iterator(); it.hasNext();) {
+            String f = RwmProperties.calcRootDir((String) it.next());
+            try {
+                File f1 = new File(new File(new URI(f)), "src/main/resources/META-INF/cocoon/xpatch");
+                File[] xmlFiles = f1.listFiles(new FilenameFilter() {
+                    public boolean accept(File d, String name) {
+                        return name.toLowerCase().endsWith(".xweb");
+                    }
+                }); 
+                if(xmlFiles != null) {
+                    File[] mergedArray = new File[allXPatchFiles.length + xmlFiles.length];
+                    System.arraycopy(allXPatchFiles, 0, mergedArray, 0, allXPatchFiles.length);
+                    System.arraycopy(xmlFiles, 0, mergedArray, allXPatchFiles.length, xmlFiles.length);
+                    allXPatchFiles = mergedArray;
+                }
+            } catch (URISyntaxException e) {
+            }
+        }
+        
+        Map libs = AbstractDeployMojo.getBlockArtifactsAsMap(this.project, this.getLog());
+        AbstractDeployMojo.xpatch(libs, allXPatchFiles, webAppBaseDir, this.getLog());
+    }
+    
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ utility methods ~~~~~~~~~~
 
     protected Set getDependencies(final String groupId, final String artifactId, final String version,
             final String packaging) throws MojoExecutionException {
@@ -398,7 +435,6 @@
 
     protected InputStream readResourceFromClassloader(String fileName) {
         String resource = ReloadingWebappMojo.class.getPackage().getName().replace('.', '/') + "/" + fileName;
-        System.out.println("Reading resource from classpath: " + resource);
         return ReloadingWebappMojo.class.getClassLoader().getResourceAsStream(resource);
     }
 

Modified: cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/rcl/RwmProperties.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/rcl/RwmProperties.java?view=diff&rev=534014&r1=533959&r2=534014
==============================================================================
--- cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/rcl/RwmProperties.java (original)
+++ cocoon/trunk/tools/cocoon-maven-plugin/src/main/java/org/apache/cocoon/maven/rcl/RwmProperties.java Tue May  1 04:35:26 2007
@@ -113,11 +113,7 @@
                             " property can only point to a directory that ends with " + TARGET_CLASSES_DIR + ".");
                 }
                 
-                // path calculation
-                if(path.endsWith("/")) {
-                    path = path.substring(0, path.length() - 1);
-                }
-                path = path.substring(0, path.length() - "target/classes".length());
+                path = calcRootDir(path);
                 
                 String newKey = key.substring(0, key.length() - CLASSES_DIR.length()) + BLOCK_CONTEXT_URL_PARAM;                
                 springProps.put(newKey, path + COB_INF_DIR);
@@ -130,6 +126,15 @@
             
         } 
         return springProps;
+    }
+
+    public static String calcRootDir(String path) {
+        // path calculation
+        if(path.endsWith("/")) {
+            path = path.substring(0, path.length() - 1);
+        }
+        path = path.substring(0, path.length() - "target/classes".length());
+        return path;
     }    
 
     public Properties getCocoonProperties() {