Index: D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/XMLUtils.java =================================================================== --- D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/XMLUtils.java (revision 0) +++ D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/XMLUtils.java (revision 0) @@ -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.maven.plugin.war; + +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 Property changes on: D:\dev\workspace\maven-war-plugin\src\main\java\org\apache\maven\plugin\war\XMLUtils.java ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/AbstractWarMojo.java =================================================================== --- D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/AbstractWarMojo.java (revision 471031) +++ D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/AbstractWarMojo.java (working copy) @@ -153,6 +153,20 @@ */ protected ArchiverManager archiverManager; + /** + * Use shielded classloading + * + * @parameter expression="${maven.war.shieldingclassloader}" + */ + private boolean useShieldingClassLoader = false; + + /** + * Move jars for shielded classloading + * + * @parameter expression="${maven.war.shieldingrepository}" + */ + private boolean useShieldingRepository = true; + private static final String WEB_INF = "WEB-INF"; private static final String META_INF = "META-INF"; @@ -626,6 +640,12 @@ copyDependentWarContents( (File) iter.next(), webappDirectory ); } } + + // check for shielded class loading + if ( this.useShieldingClassLoader ) + { + WebApplicationRewriter.shieldWebapp(webinfDir, this.getLog(), this.useShieldingRepository); + } } /** @@ -1025,9 +1045,16 @@ */ private String getDefaultFinalName( Artifact artifact ) { - return artifact.getArtifactId() + "-" + artifact.getVersion() + "." + - artifact.getArtifactHandler().getExtension(); + String finalName = artifact.getArtifactId() + "-" + artifact.getVersion(); + + String classifier = artifact.getClassifier(); + if ( ( classifier != null ) && ! ( "".equals( classifier.trim() ) ) ) + { + finalName += "-" + classifier; + } + + finalName = finalName + "." + artifact.getArtifactHandler().getExtension(); + return finalName; } - } Index: D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldingServletFilter.java =================================================================== --- D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldingServletFilter.java (revision 0) +++ D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldingServletFilter.java (revision 0) @@ -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.maven.plugin.war.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 Property changes on: D:\dev\workspace\maven-war-plugin\src\main\java\org\apache\maven\plugin\war\servlet\ShieldingServletFilter.java ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldedClassLoaderManager.java =================================================================== --- D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldedClassLoaderManager.java (revision 0) +++ D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldedClassLoaderManager.java (revision 0) @@ -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.maven.plugin.war.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: + * + * + * @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; + } + } +} Property changes on: D:\dev\workspace\maven-war-plugin\src\main\java\org\apache\maven\plugin\war\servlet\ShieldedClassLoaderManager.java ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldingServlet.java =================================================================== --- D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldingServlet.java (revision 0) +++ D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldingServlet.java (revision 0) @@ -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.maven.plugin.war.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. + *

+ * + * @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 Property changes on: D:\dev\workspace\maven-war-plugin\src\main\java\org\apache\maven\plugin\war\servlet\ShieldingServlet.java ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldingListener.java =================================================================== --- D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldingListener.java (revision 0) +++ D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldingListener.java (revision 0) @@ -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.maven.plugin.war.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 Property changes on: D:\dev\workspace\maven-war-plugin\src\main\java\org\apache\maven\plugin\war\servlet\ShieldingListener.java ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldedClassLoader.java =================================================================== --- D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldedClassLoader.java (revision 0) +++ D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/servlet/ShieldedClassLoader.java (revision 0) @@ -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.maven.plugin.war.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; + } +} + Property changes on: D:\dev\workspace\maven-war-plugin\src\main\java\org\apache\maven\plugin\war\servlet\ShieldedClassLoader.java ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/WebApplicationRewriter.java =================================================================== --- D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/WebApplicationRewriter.java (revision 0) +++ D:/dev/workspace/maven-war-plugin/src/main/java/org/apache/maven/plugin/war/WebApplicationRewriter.java (revision 0) @@ -0,0 +1,344 @@ +/* + * 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.maven.plugin.war; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.plugin.war.servlet.ShieldedClassLoaderManager; +import org.apache.maven.plugin.war.servlet.ShieldingListener; +import org.apache.maven.plugin.war.servlet.ShieldingServlet; +import org.apache.maven.plugin.war.servlet.ShieldingServletFilter; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.IOUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * @version $Id$ + */ +public class WebApplicationRewriter { + + protected static final String SERVLET_CLASS = ShieldingServlet.class.getName(); + + protected static final String LISTENER_CLASS = ShieldingListener.class.getName(); + + protected static final String FILTER_CLASS = ShieldingServletFilter.class.getName(); + + protected static final String CLASSLOADER_JAR = "maven-war-plugin-classloading.jar"; + + protected static final String JAR_ENTRY_PREFIX = ShieldedClassLoaderManager.class.getPackage().getName().replace('.', '/'); + + /** + * Prepare the web application to use the shielded class loader. + * The web.xml will be rewritten: all servlets, filters etc. are wrapped + * by a wrapper which uses the shielded class loader. + * In addition all libs are moved from WEB-INF/lib to WEB-INF/shielded/lib + * and all files from WEB-INF/classes are moved to WEB-INF/shielded/classes. + */ + public static void shieldWebapp(File webInfDir, Log log, boolean useShieldingRepository) + throws MojoExecutionException { + final String webInfSlashWebXml = webInfDir.getPath() + File.separatorChar + "web.xml"; + + if (!new File(webInfSlashWebXml).exists()) { + throw new MojoExecutionException("No web.xml present - can't add shielded class loading"); + } + log.info("Adding shielded classloader configuration to web application configuration."); + if ( log.isDebugEnabled() ) { + log.debug("Reading web.xml: " + webInfSlashWebXml); + } + + // load web.xml + InputStream is = null; + final Document webAppDoc; + try { + is = new BufferedInputStream(new FileInputStream(new File(webInfSlashWebXml))); + webAppDoc = XMLUtils.parseXml(is); + } catch (Exception e) { + throw new MojoExecutionException("Unable to read web.xml from " + webInfSlashWebXml, e); + } finally { + if ( is != null ) { + try { + is.close(); + } catch (IOException ignore) { + // ignore + } + } + } + + // rewrite + if ( WebApplicationRewriter.rewrite(webAppDoc, useShieldingRepository) ) { + + // save web.xml + try { + if ( log.isDebugEnabled() ) { + log.debug("Writing web.xml: " + webInfSlashWebXml); + } + XMLUtils.write(webAppDoc, new FileOutputStream(webInfSlashWebXml)); + } catch (Exception e) { + throw new MojoExecutionException("Unable to write web.xml to " + webInfSlashWebXml, e); + } + } + + // move classes and libs + if (useShieldingRepository) { + log.info("Moving classes and libs to shielded location."); + try { + move(webInfDir, "lib", ShieldedClassLoaderManager.WEB_INF_SHIELDED_LIB, log); + move(webInfDir, "classes", ShieldedClassLoaderManager.WEB_INF_SHIELDED_CLASSES, log); + } catch (IOException e) { + throw new MojoExecutionException("unable to shield classes/libs", e); + } + } + + // add classloading stuff to WEB-INF/lib + // let's search our jar + final String rsrc = ShieldedClassLoaderManager.class.getName().replace('.', '/') + ".class"; + if ( log.isDebugEnabled() ) { + log.debug("Searching class file for: " + rsrc); + } + try { + final Enumeration e = WebApplicationRewriter.class.getClassLoader().getResources(rsrc); + boolean found = false; + while ( e.hasMoreElements() ) { + final URL url = (URL)e.nextElement(); + if ( log.isDebugEnabled() ) { + log.debug("Found class in " + url); + } + if ( url.getProtocol().equals("jar")) { + String jarUrlString = url.toExternalForm(); + int pos = jarUrlString.indexOf('!'); + // include !/ + jarUrlString = jarUrlString.substring(0, pos + 2); + final URL jarUrl = new URL(jarUrlString); + final JarURLConnection connection = (JarURLConnection)jarUrl.openConnection(); + final JarFile jarFile = connection.getJarFile(); + final File destFile = new File(webInfDir, "lib" + File.separator + CLASSLOADER_JAR); + final JarOutputStream jos = new JarOutputStream(new FileOutputStream(destFile)); + final Enumeration entries = jarFile.entries(); + while ( entries.hasMoreElements() ) { + final JarEntry current = (JarEntry)entries.nextElement(); + // only include classes from the shielded class loader package + if ( current.getName().startsWith(JAR_ENTRY_PREFIX) ) { + jos.putNextEntry(current); + IOUtil.copy(jarFile.getInputStream(current), jos); + jos.closeEntry(); + } + } + jos.close(); + found = true; + } + } + if (!found) { + throw new MojoExecutionException("Unable to find jar file for shielded class loading classes."); + } + } catch (IOException ioe) { + throw new MojoExecutionException("unable to find classes for shielded class loading.", ioe); + } + } + + private static void move(File parentDir, String srcDir, String destDirOrig, Log log) throws IOException { + String destDir = destDirOrig; + // use correct separators on windows + if ( File.separatorChar != '/' ) { + destDir = destDir.replace('/', File.separatorChar); + } + final File srcDirectory = new File(parentDir, srcDir); + if (srcDirectory.exists() && srcDirectory.isDirectory()) { + File destDirectory = new File(parentDir, destDir); + if (log.isDebugEnabled()) { + log.debug("Deleting directory " + destDirectory); + } + FileUtils.deleteDirectory(destDirectory); + destDirectory = new File(parentDir, destDir); + if (log.isDebugEnabled()) { + log.debug("Recreating directory " + destDirectory); + } + destDirectory.mkdirs(); + final File[] files = srcDirectory.listFiles(); + if (files != null && files.length > 0) { + for (int i = 0; i < files.length; i++) { + // move everything but our own jar + if ( !files[i].getName().equals(CLASSLOADER_JAR) ) { + if (log.isDebugEnabled()) { + log.debug("Moving " + files[i] + " to " + destDirectory); + } + files[i].renameTo(new File(destDirectory, files[i].getName())); + } + } + } + } + } + + public static boolean rewrite(Document webAppDoc, boolean useShieldingRepository) { + boolean rewritten = false; + final Element rootElement = webAppDoc.getDocumentElement(); + // first rewrite servlets + final List servlets = XMLUtils.getChildNodes(rootElement, "servlet"); + Iterator i = servlets.iterator(); + while ( i.hasNext() ) { + final Element servletElement = (Element)i.next(); + final Element servletClassElement = XMLUtils.getChildNode(servletElement, "servlet-class"); + if ( servletClassElement != null ) { + final String className = XMLUtils.getValue(servletClassElement); + XMLUtils.setValue(servletClassElement, SERVLET_CLASS); + // create init-param with real servlet class + final Element initParamElem = webAppDoc.createElementNS(null, "init-param"); + final Element initParamNameElem = webAppDoc.createElementNS(null, "param-name"); + final Element initParamValueElem = webAppDoc.createElementNS(null, "param-value"); + initParamElem.appendChild(initParamNameElem); + initParamElem.appendChild(initParamValueElem); + XMLUtils.setValue(initParamNameElem, "servlet-class"); + XMLUtils.setValue(initParamValueElem, className); + Element beforeElement = XMLUtils.getChildNode(servletElement, "load-on-startup"); + if ( beforeElement == null ) { + beforeElement = XMLUtils.getChildNode(servletElement, "run-as"); + if ( beforeElement == null ) { + beforeElement = XMLUtils.getChildNode(servletElement, "security-role-ref"); + } + } + if ( beforeElement == null ) { + servletElement.appendChild(initParamElem); + } else { + servletElement.insertBefore(initParamElem, beforeElement); + } + rewritten = true; + } + } + + // now rewrite listeners + final List listeners = XMLUtils.getChildNodes(rootElement, "listener"); + i = listeners.iterator(); + boolean hasListener = false; + final StringBuffer rewrittenListeners = new StringBuffer(); + while ( i.hasNext() ) { + final Element listenerElement = (Element)i.next(); + final Element listenerClassElement = XMLUtils.getChildNode(listenerElement, "listener-class"); + if ( listenerClassElement != null ) { + final String className = XMLUtils.getValue(listenerClassElement); + if ( rewrittenListeners.length() > 0 ) { + rewrittenListeners.append(','); + } + rewrittenListeners.append(className); + if ( hasListener ) { + rootElement.removeChild(listenerElement); + } else { + XMLUtils.setValue(listenerClassElement, LISTENER_CLASS); + hasListener = true; + } + rewritten = true; + } + } + // remove old parameter + i = XMLUtils.getChildNodes(rootElement, "context-param").iterator(); + while ( i.hasNext() ) { + final Element child = (Element)i.next(); + if ( LISTENER_CLASS.equals(XMLUtils.getValue(XMLUtils.getChildNode(child, "param-name")))) { + rootElement.removeChild(child); + } + } + if ( hasListener ) { + addContextParameter(rootElement, LISTENER_CLASS, rewrittenListeners.toString()); + } + + // and now filters + i = XMLUtils.getChildNodes(rootElement, "filter").iterator(); + while ( i.hasNext() ) { + final Element filterElement = (Element)i.next(); + final Element filterClassElement = XMLUtils.getChildNode(filterElement, "filter-class"); + if ( filterClassElement != null ) { + final String className = XMLUtils.getValue(filterClassElement); + XMLUtils.setValue(filterClassElement, FILTER_CLASS); + // create init-param with real servlet class + final Element initParamElem = webAppDoc.createElementNS(null, "init-param"); + final Element initParamNameElem = webAppDoc.createElementNS(null, "param-name"); + final Element initParamValueElem = webAppDoc.createElementNS(null, "param-value"); + initParamElem.appendChild(initParamNameElem); + initParamElem.appendChild(initParamValueElem); + XMLUtils.setValue(initParamNameElem, "filter-class"); + XMLUtils.setValue(initParamValueElem, className); + filterElement.appendChild(initParamElem); + rewritten = true; + } + } + + if ( !useShieldingRepository ) { + addContextParameter(rootElement, + ShieldedClassLoaderManager.SHIELDED_CLASSLOADER_USE_REPOSITORY, + "false"); + rewritten = true; + } else { + if ( removeContextParameter(rootElement, ShieldedClassLoaderManager.SHIELDED_CLASSLOADER_USE_REPOSITORY) ) { + rewritten = true; + } + } + + return rewritten; + } + + protected static boolean removeContextParameter(Element root, String name) { + boolean removed = false; + final Iterator i = XMLUtils.getChildNodes(root, "context-param").iterator(); + while ( !removed && i.hasNext() ) { + final Element parameterElement = (Element)i.next(); + final String paramName = XMLUtils.getValue(XMLUtils.getChildNode(parameterElement, "param-name")); + if ( name.equals(paramName) ) { + parameterElement.getParentNode().removeChild(parameterElement); + removed = true; + } + } + return removed; + } + + protected static void addContextParameter(Element root, String name, String value) { + removeContextParameter(root, name); + // search the element where we have to put the new context parameter before! + // we know that we have listeners so this is the last element to search for + Element searchElement = XMLUtils.getChildNode(root, "context-param"); + if ( searchElement == null ) { + searchElement = XMLUtils.getChildNode(root, "filter"); + if ( searchElement == null ) { + searchElement = XMLUtils.getChildNode(root, "filter-mapping"); + if ( searchElement == null ) { + searchElement = XMLUtils.getChildNode(root, "listener"); + } + } + } + final Element contextParamElement = root.getOwnerDocument().createElementNS(null, "context-param"); + final Element contextParamNameElement = root.getOwnerDocument().createElementNS(null, "param-name"); + final Element contextParamValueElement = root.getOwnerDocument().createElementNS(null, "param-value"); + contextParamElement.appendChild(contextParamNameElement); + contextParamElement.appendChild(contextParamValueElement); + XMLUtils.setValue(contextParamNameElement, name); + XMLUtils.setValue(contextParamValueElement, value); + root.insertBefore(contextParamElement, searchElement); + } +} \ No newline at end of file Property changes on: D:\dev\workspace\maven-war-plugin\src\main\java\org\apache\maven\plugin\war\WebApplicationRewriter.java ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: D:/dev/workspace/maven-war-plugin/pom.xml =================================================================== --- D:/dev/workspace/maven-war-plugin/pom.xml (revision 471031) +++ D:/dev/workspace/maven-war-plugin/pom.xml (working copy) @@ -38,6 +38,12 @@ 2.0.1 + javax.servlet + servlet-api + 2.4 + compile + + junit junit 3.8.1