Return-Path: Delivered-To: apmail-cocoon-cvs-archive@www.apache.org Received: (qmail 87874 invoked from network); 1 May 2007 11:35:53 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 1 May 2007 11:35:53 -0000 Received: (qmail 91517 invoked by uid 500); 1 May 2007 11:35:58 -0000 Delivered-To: apmail-cocoon-cvs-archive@cocoon.apache.org Received: (qmail 91458 invoked by uid 500); 1 May 2007 11:35:58 -0000 Mailing-List: contact cvs-help@cocoon.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@cocoon.apache.org list-help: list-unsubscribe: List-Post: List-Id: Delivered-To: mailing list cvs@cocoon.apache.org Received: (qmail 91429 invoked by uid 99); 1 May 2007 11:35:58 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 01 May 2007 04:35:58 -0700 X-ASF-Spam-Status: No, hits=-99.5 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 01 May 2007 04:35:49 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id DE27E1A983E; Tue, 1 May 2007 04:35:28 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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... Date: Tue, 01 May 2007 11:35:27 -0000 To: cvs@cocoon.apache.org From: reinhard@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20070501113528.DE27E1A983E@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 URLs. + */ + public ShieldedClassLoader(URL[] urls, final ClassLoader parent) { + this(urls, parent, null); + } + + /** + * Alternate constructor to define a parent, initial URLs, + * and a default URLStreamHandlerFactory. + */ + 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 ClassLoader. If the + * class does not exist in this one, we check the parent. Please + * note that this is the exact opposite of the + * ClassLoader spec. We use it to work around + * inconsistent class loaders from third party vendors. + * + * @param name the name of the class + * @param resolve if true then resolve the class + * @return the resulting Class 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 ClassLoader. If the + * resource does not exist in this one, we check the parent. + * Please note that this is the exact opposite of the + * ClassLoader 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: + *
    + *
  • shielded-classloader-debug Can be used to turn debug messages on.
  • + *
+ * + * @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. + *

+ * This servlet propagates all initialisation parameters to the sandboxed + * servlet, and requires the parameter servlet-class. + *

    + *
  • servlet-class defines the sandboxed servlet class.
  • + *
+ * + * @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 int []. */ + protected static final int MATCH_FILE = -1; + /** The int representing '**' in the pattern int []. */ + protected static final int MATCH_PATH = -2; + /** The int representing begin in the pattern int []. */ + protected static final int MATCH_BEGIN = -4; + /** The int representing end in pattern int []. */ + protected static final int MATCH_THEEND = -5; + /** The int value that terminates the pattern int []. */ + protected static final int MATCH_END = -3; + + + /** + * Translate the given String into a int [] + * representing the pattern matchable by this class. + *
+ * This function translates a String into an int array + * converting the special '*' and '\' characters. + *
+ * Here is how the conversion algorithm works: + *
    + *
  • The '*' character is converted to MATCH_FILE, meaning that zero + * or more characters (excluding the path separator '/') are to + * be matched.
  • + *
  • The '**' sequence is converted to MATCH_PATH, meaning that zero + * or more characters (including the path separator '/') are to + * be matched.
  • + *
  • 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.
  • + *
+ * When more than two '*' characters, not separated by another character, + * are found their value is considered as '**' (MATCH_PATH). + *
+ * The array is always terminated by a special value (MATCH_END). + *
+ * 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 + * Stack. + */ + 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. + *
+ * 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. + *
+ * 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. + *
+ * 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() {