diff options
author | Jan Bartel | 2010-07-16 07:15:13 +0000 |
---|---|---|
committer | Jan Bartel | 2010-07-16 07:15:13 +0000 |
commit | 314f94decc0e814baf31f500502020e05fcb73a2 (patch) | |
tree | c2cd339dc135614dcc16c0e5a19d81352ff3ee02 /jetty-webapp | |
parent | 8210d068c43058097970fae131643df6b9d9dbdf (diff) | |
download | org.eclipse.jetty.project-314f94decc0e814baf31f500502020e05fcb73a2.tar.gz org.eclipse.jetty.project-314f94decc0e814baf31f500502020e05fcb73a2.tar.xz org.eclipse.jetty.project-314f94decc0e814baf31f500502020e05fcb73a2.zip |
320073 Reconcile jetty-8 and jetty-7 webapp configuration mechanisms
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2145 7e9141cc-0065-0410-87d8-b60c137991c4
Diffstat (limited to 'jetty-webapp')
17 files changed, 3945 insertions, 1139 deletions
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DefaultsDescriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DefaultsDescriptor.java new file mode 100644 index 0000000000..e7331f6972 --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DefaultsDescriptor.java @@ -0,0 +1,29 @@ +// ======================================================================== +// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import org.eclipse.jetty.util.resource.Resource; + +/** + * DefaultsDescriptor + * + * + */ +public class DefaultsDescriptor extends Descriptor +{ + public DefaultsDescriptor(Resource xml, MetaData processor) + { + super(xml, processor); + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java new file mode 100644 index 0000000000..e6aca3c819 --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java @@ -0,0 +1,290 @@ +// ======================================================================== +// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.Servlet; + +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.xml.XmlParser; + + + +/** + * Descriptor + * + * A web descriptor (web.xml/web-defaults.xml/web-overrides.xml). + */ +public class Descriptor +{ + protected static XmlParser _parser; + public enum MetaDataComplete {NotSet, True, False}; + protected Resource _xml; + protected XmlParser.Node _root; + protected MetaDataComplete _metaDataComplete; + protected int _majorVersion = 3; //default to container version + protected int _minorVersion = 0; + protected ArrayList<String> _classNames = new ArrayList<String>(); + protected boolean _distributable; + protected boolean _validating; + protected MetaData _metaData; + protected boolean _isOrdered = false; + protected List<String> _ordering = new ArrayList<String>(); + + + + + public static XmlParser newParser() + throws ClassNotFoundException + { + XmlParser xmlParser=new XmlParser(); + //set up cache of DTDs and schemas locally + URL dtd22=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_2.dtd",true); + URL dtd23=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_3.dtd",true); + URL j2ee14xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_1_4.xsd",true); + URL webapp24xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_4.xsd",true); + URL webapp25xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_5.xsd",true); + URL webapp30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_3_0.xsd",true); + URL webcommon30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-common_3_0.xsd",true); + URL webfragment30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-fragment_3_0.xsd",true); + URL schemadtd=Loader.getResource(Servlet.class,"javax/servlet/resources/XMLSchema.dtd",true); + URL xmlxsd=Loader.getResource(Servlet.class,"javax/servlet/resources/xml.xsd",true); + URL webservice11xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_web_services_client_1_1.xsd",true); + URL webservice12xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/javaee_web_services_client_1_2.xsd",true); + URL datatypesdtd=Loader.getResource(Servlet.class,"javax/servlet/resources/datatypes.dtd",true); + + URL jsp20xsd = null; + URL jsp21xsd = null; + + try + { + Class jsp_page = Loader.loadClass(WebXmlConfiguration.class, "javax.servlet.jsp.JspPage"); + jsp20xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_0.xsd"); + jsp21xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_1.xsd"); + } + catch (Exception e) + { + Log.ignore(e); + } + finally + { + if (jsp20xsd == null) jsp20xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_0.xsd", true); + if (jsp21xsd == null) jsp21xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_1.xsd", true); + } + + redirect(xmlParser,"web-app_2_2.dtd",dtd22); + redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22); + redirect(xmlParser,"web.dtd",dtd23); + redirect(xmlParser,"web-app_2_3.dtd",dtd23); + redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23); + redirect(xmlParser,"XMLSchema.dtd",schemadtd); + redirect(xmlParser,"http://www.w3.org/2001/XMLSchema.dtd",schemadtd); + redirect(xmlParser,"-//W3C//DTD XMLSCHEMA 200102//EN",schemadtd); + redirect(xmlParser,"jsp_2_0.xsd",jsp20xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd",jsp20xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/jsp_2_1.xsd",jsp21xsd); + redirect(xmlParser,"j2ee_1_4.xsd",j2ee14xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd",j2ee14xsd); + redirect(xmlParser,"web-app_2_4.xsd",webapp24xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd",webapp24xsd); + redirect(xmlParser,"web-app_2_5.xsd",webapp25xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd",webapp25xsd); + redirect(xmlParser,"web-app_3_0.xsd",webapp30xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd",webapp30xsd); + redirect(xmlParser,"web-common_3_0.xsd",webcommon30xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-common_3_0.xsd",webcommon30xsd); + redirect(xmlParser,"web-fragment_3_0.xsd",webfragment30xsd); + redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd",webfragment30xsd); + redirect(xmlParser,"xml.xsd",xmlxsd); + redirect(xmlParser,"http://www.w3.org/2001/xml.xsd",xmlxsd); + redirect(xmlParser,"datatypes.dtd",datatypesdtd); + redirect(xmlParser,"http://www.w3.org/2001/datatypes.dtd",datatypesdtd); + redirect(xmlParser,"j2ee_web_services_client_1_1.xsd",webservice11xsd); + redirect(xmlParser,"http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd",webservice11xsd); + redirect(xmlParser,"javaee_web_services_client_1_2.xsd",webservice12xsd); + redirect(xmlParser,"http://www.ibm.com/webservices/xsd/javaee_web_services_client_1_2.xsd",webservice12xsd); + return xmlParser; + } + + + protected static void redirect(XmlParser parser, String resource, URL source) + { + if (source != null) parser.redirectEntity(resource, source); + } + + + + public Descriptor (Resource xml, MetaData md) + { + _xml = xml; + _metaData = md; + } + + public void parse () + throws Exception + { + if (_parser == null) + _parser = newParser(); + + if (_root == null) + { + //boolean oldValidating = _processor.getParser().getValidating(); + //_processor.getParser().setValidating(_validating); + _root = _parser.parse(_xml.getURL().toString()); + processVersion(); + processOrdering(); + //_processor.getParser().setValidating(oldValidating); + } + } + + public MetaDataComplete getMetaDataComplete() + { + return _metaDataComplete; + } + + + public XmlParser.Node getRoot () + { + return _root; + } + + public int getMajorVersion () + { + return _majorVersion; + } + + public int getMinorVersion() + { + return _minorVersion; + } + + public Resource getResource () + { + return _xml; + } + + public MetaData getMetaData() + { + return _metaData; + } + + public void processVersion () + { + String version = _root.getAttribute("version", "DTD"); + if ("DTD".equals(version)) + { + _majorVersion = 2; + _minorVersion = 3; + String dtd = _parser.getDTD(); + if (dtd != null && dtd.indexOf("web-app_2_2") >= 0) + { + _majorVersion = 2; + _minorVersion = 2; + } + } + else + { + int dot = version.indexOf("."); + if (dot > 0) + { + _majorVersion = Integer.parseInt(version.substring(0,dot)); + _minorVersion = Integer.parseInt(version.substring(dot+1)); + } + } + + if (_majorVersion < 2 && _minorVersion < 5) + _metaDataComplete = MetaDataComplete.True; // does not apply before 2.5 + else + { + String s = (String)_root.getAttribute("metadata-complete"); + if (s == null) + _metaDataComplete = MetaDataComplete.NotSet; + else + _metaDataComplete = Boolean.valueOf(s).booleanValue()?MetaDataComplete.True:MetaDataComplete.False; + } + + Log.debug(_xml.toString()+": Calculated metadatacomplete = " + _metaDataComplete + " with version=" + version); + } + + public void processOrdering () + { + //Process the web.xml's optional <absolute-ordering> element + XmlParser.Node ordering = _root.get("absolute-ordering"); + if (ordering == null) + return; + + _isOrdered = true; + //If an absolute-ordering was already set, then ignore it in favour of this new one + // _processor.setOrdering(new AbsoluteOrdering()); + + Iterator iter = ordering.iterator(); + XmlParser.Node node = null; + while (iter.hasNext()) + { + Object o = iter.next(); + if (!(o instanceof XmlParser.Node)) continue; + node = (XmlParser.Node) o; + + if (node.getTag().equalsIgnoreCase("others")) + //((AbsoluteOrdering)_processor.getOrdering()).addOthers(); + _ordering.add("others"); + else if (node.getTag().equalsIgnoreCase("name")) + //((AbsoluteOrdering)_processor.getOrdering()).add(node.toString(false,true)); + _ordering.add(node.toString(false,true)); + } + } + + public void addClassName (String className) + { + if (!_classNames.contains(className)) + _classNames.add(className); + } + + public ArrayList<String> getClassNames () + { + return _classNames; + } + + public void setDistributable (boolean distributable) + { + _distributable = distributable; + } + + public boolean isDistributable() + { + return _distributable; + } + + public void setValidating (boolean validating) + { + _validating = validating; + } + + + public boolean isOrdered() + { + return _isOrdered; + } + + public List<String> getOrdering() + { + return _ordering; + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DescriptorProcessor.java new file mode 100644 index 0000000000..88a0e143d5 --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DescriptorProcessor.java @@ -0,0 +1,24 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +/** + * DescriptorProcessor + * + * + */ +public interface DescriptorProcessor +{ + public void process (Descriptor descriptor) throws Exception; +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java new file mode 100644 index 0000000000..2e1a1535b1 --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/DiscoveredAnnotation.java @@ -0,0 +1,68 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.log.Log; + +/** + * DiscoveredAnnotation + * + * Represents an annotation that has been discovered + * by scanning source code of WEB-INF/classes and WEB-INF/lib jars. + * + */ +public abstract class DiscoveredAnnotation +{ + protected WebAppContext _context; + protected String _className; + protected Class _clazz; + + public abstract void apply(); + + public DiscoveredAnnotation (WebAppContext context, String className) + { + _context = context; + _className = className; + } + + + public Class getTargetClass() + { + if (_clazz != null) + return _clazz; + + loadClass(); + + return _clazz; + } + + private void loadClass () + { + if (_clazz != null) + return; + + if (_className == null) + return; + + try + { + _clazz = Loader.loadClass(null, _className); + } + catch (Exception e) + { + Log.warn(e); + } + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java index 47a2d9f81c..4828738c94 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java @@ -21,7 +21,7 @@ import org.eclipse.jetty.util.resource.Resource; /** * FragmentConfiguration * - * This configuration supports some Servlet 3.0 features in jetty-7. + * * * Process web-fragments in jars */ @@ -33,20 +33,14 @@ public class FragmentConfiguration implements Configuration { if (!context.isConfigurationDiscovered()) return; + + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException("No metadata"); + + //find all web-fragment.xmls + findWebFragments(context, metaData); - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (processor == null) - { - processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); - } - - - //parse web-fragment.xmls - parseWebFragments(context, processor); - - //TODO for jetty-8/servletspec 3 we will need to merge the parsed web fragments into the - //effective pom in this preConfigure step } public void configure(WebAppContext context) throws Exception @@ -54,16 +48,12 @@ public class FragmentConfiguration implements Configuration if (!context.isConfigurationDiscovered()) return; - //TODO for jetty-8/servletspec3 the fragments will not be separately processed here, but - //will be done by webXmlConfiguration when it processes the effective merged web.xml - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (processor == null) - { - processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); - } - - processor.processFragments(); + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException("No metadata"); + + //order the fragments + metaData.orderFragments(); } public void deconfigure(WebAppContext context) throws Exception @@ -78,20 +68,19 @@ public class FragmentConfiguration implements Configuration /* ------------------------------------------------------------------------------- */ /** - * Look for any web.xml fragments in META-INF of jars in WEB-INF/lib + * Look for any web-fragment.xml fragments in META-INF of jars in WEB-INF/lib * * @throws Exception */ - public void parseWebFragments (final WebAppContext context, final WebXmlProcessor processor) throws Exception + public void findWebFragments (final WebAppContext context, final MetaData metaData) throws Exception { List<Resource> frags = (List<Resource>)context.getAttribute(FRAGMENT_RESOURCES); if (frags!=null) { for (Resource frag : frags) { - processor.parseFragment(Resource.newResource("jar:"+frag.getURL()+"!/META-INF/web-fragment.xml")); + metaData.addFragment(frag, Resource.newResource("jar:"+frag.getURL()+"!/META-INF/web-fragment.xml")); } } } - } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentDescriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentDescriptor.java new file mode 100644 index 0000000000..75c36de57a --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentDescriptor.java @@ -0,0 +1,162 @@ +// ======================================================================== +// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.xml.XmlParser; + + +/** + * Fragment + * + * A web-fragment.xml descriptor. + */ +public class FragmentDescriptor extends Descriptor +{ + public static final String NAMELESS = "@@-NAMELESS-@@"; //prefix for nameless Fragments + public enum OtherType {None, Before, After}; + + protected int _counter = 0; + protected OtherType _otherType = OtherType.None; + + + protected List<String> _befores = new ArrayList<String>(); + protected List<String> _afters = new ArrayList<String>(); + protected String _name; + + + public FragmentDescriptor (Resource xml, MetaData processor) + throws Exception + { + super (xml, processor); + } + + public String getName () + { + return _name; + } + + public void parse () + throws Exception + { + super.parse(); + processName(); + } + + public void processName () + { + XmlParser.Node root = getRoot(); + XmlParser.Node nameNode = root.get("name"); + _name = NAMELESS+(_counter++); + if (nameNode != null) + { + String tmp = nameNode.toString(false,true); + if (tmp!=null && tmp.length()>0) + _name = tmp; + } + } + public void processOrdering () + { + //Process a fragment jar's web-fragment.xml<ordering> elements + XmlParser.Node root = getRoot(); + + XmlParser.Node ordering = root.get("ordering"); + if (ordering == null) + return; //No ordering for this fragment + + _isOrdered = true; + + processBefores(ordering); + processAfters(ordering); + } + + + public void processBefores (XmlParser.Node ordering) + { + //Process the <before> elements, looking for an <others/> clause and all of the <name> clauses + XmlParser.Node before = ordering.get("before"); + if (before == null) + return; + + Iterator iter = before.iterator(); + XmlParser.Node node = null; + while (iter.hasNext()) + { + Object o = iter.next(); + if (!(o instanceof XmlParser.Node)) continue; + node = (XmlParser.Node) o; + if (node.getTag().equalsIgnoreCase("others")) + { + if (_otherType != OtherType.None) + throw new IllegalStateException("Duplicate <other> clause detected in "+_xml.getURI()); + + _otherType = OtherType.Before; + } + else if (node.getTag().equalsIgnoreCase("name")) + _befores.add(node.toString(false,true)); + } + } + + public void processAfters (XmlParser.Node ordering) + { + //Process the <after> elements, look for an <others/> clause and all of the <name/> clauses + XmlParser.Node after = ordering.get("after"); + if (after == null) + return; + + Iterator iter = after.iterator(); + XmlParser.Node node = null; + while (iter.hasNext()) + { + Object o = iter.next(); + if (!(o instanceof XmlParser.Node)) continue; + node = (XmlParser.Node) o; + if (node.getTag().equalsIgnoreCase("others")) + { + if (_otherType != OtherType.After) + throw new IllegalStateException("Duplicate <other> clause detected in "+_xml.getURI()); + + _otherType = OtherType.After; + + } + else if (node.getTag().equalsIgnoreCase("name")) + _afters.add(node.toString(false,true)); + } + } + + public List<String> getBefores() + { + return Collections.unmodifiableList(_befores); + } + + public List<String> getAfters() + { + return Collections.unmodifiableList(_afters); + } + + public OtherType getOtherType () + { + return _otherType; + } + + public List<String> getOrdering() + { + return null; //only used for absolute-ordering in Descriptor + } +}
\ No newline at end of file diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java new file mode 100644 index 0000000000..fd1507649e --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java @@ -0,0 +1,84 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.jetty.xml.XmlParser; + +/** + * IterativeDescriptorProcessor + * + * + */ +public abstract class IterativeDescriptorProcessor implements DescriptorProcessor +{ + public static final Class[] __signature = new Class[]{Descriptor.class, XmlParser.Node.class}; + protected Map<String, Method> _visitors = new HashMap<String, Method>(); + public abstract void start(Descriptor descriptor); + public abstract void end(Descriptor descriptor); + + /** + * Register a method to be called back when visiting the node with the given name. + * The method must exist on a subclass of this class, and must have the signature: + * public void method (Descriptor descriptor, XmlParser.Node node) + * @param nodeName + * @param m + */ + public void registerVisitor(String nodeName, Method m) + { + _visitors.put(nodeName, m); + } + + + /** + * @see org.eclipse.jetty.webapp.DescriptorProcessor#process(org.eclipse.jetty.webapp.Descriptor) + */ + public void process(Descriptor descriptor) + throws Exception + { + if (descriptor == null) + return; + + start(descriptor); + + XmlParser.Node root = descriptor.getRoot(); + Iterator iter = root.iterator(); + XmlParser.Node node = null; + while (iter.hasNext()) + { + Object o = iter.next(); + if (!(o instanceof XmlParser.Node)) continue; + node = (XmlParser.Node) o; + visit(descriptor, node); + } + + end(descriptor); + } + + + protected void visit (final Descriptor descriptor, final XmlParser.Node node) + throws Exception + { + String name = node.getTag(); + Method m = _visitors.get(name); + if (m != null) + m.invoke(this, new Object[]{descriptor, node}); + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java index 27aa287e17..10bcfad5a9 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java @@ -25,7 +25,7 @@ import org.eclipse.jetty.xml.XmlConfiguration; * * JettyWebConfiguration. * - * Looks for Xmlconfiguration files in WEB-INF. Searches in order for the first of jetty6-web.xml, jetty-web.xml or web-jetty.xml + * Looks for Xmlconfiguration files in WEB-INF. Searches in order for the first of jettyX-web.xml, jetty-web.xml or web-jetty.xml * * * diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java new file mode 100644 index 0000000000..b240b190d7 --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java @@ -0,0 +1,911 @@ +// ======================================================================== +// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.eclipse.jetty.util.resource.Resource; + + + + + +/** + * MetaData + * + * + */ +public class MetaData +{ + public static final String METADATA = "org.eclipse.jetty.metaData"; + public static final String METADATA_COMPLETE = "org.eclipse.jetty.metadataComplete"; + public static final String WEBXML_MAJOR_VERSION = "org.eclipse.jetty.webXmlMajorVersion"; + public static final String WEBXML_MINOR_VERSION = "org.eclipse.jetty.webXmlMinorVersion"; + public static final String WEBXML_CLASSNAMES = "org.eclipse.jetty.webXmlClassNames"; + public static final String ORDERED_LIBS = "javax.servlet.context.orderedLibs"; + + public enum Origin {NotSet, WebXml, WebDefaults, WebOverride, WebFragment, Annotation}; + + protected WebAppContext _context; + protected Map<String, OriginInfo> _origins = new HashMap<String,OriginInfo>(); + protected Descriptor _webDefaultsRoot; + protected Descriptor _webXmlRoot; + protected Descriptor _webOverrideRoot; + protected List<DiscoveredAnnotation> _annotations = new ArrayList<DiscoveredAnnotation>(); + protected List<DescriptorProcessor> _descriptorProcessors = new ArrayList<DescriptorProcessor>(); + protected List<FragmentDescriptor> _webFragmentRoots = new ArrayList<FragmentDescriptor>(); + protected Map<String,FragmentDescriptor> _webFragmentNameMap = new HashMap<String,FragmentDescriptor>(); + protected Map<Resource, FragmentDescriptor> _webFragmentResourceMap = new HashMap<Resource, FragmentDescriptor>(); + protected Map<Resource, List<DiscoveredAnnotation>> _webFragmentAnnotations = new HashMap<Resource, List<DiscoveredAnnotation>>(); + protected List<Resource> _orderedResources; + protected Ordering _ordering;//can be set to RelativeOrdering by web-default.xml, web.xml, web-override.xml + protected StandardDescriptorProcessor _standardDescriptorProcessor; + + + public static class OriginInfo + { + protected String name; + protected Origin origin; + protected Descriptor descriptor; + + public OriginInfo (String n, Descriptor d) + { + name = n; + descriptor = d; + if (d == null) + throw new IllegalArgumentException("No descriptor"); + if (d instanceof FragmentDescriptor) + origin = Origin.WebFragment; + if (d instanceof OverrideDescriptor) + origin = Origin.WebOverride; + if (d instanceof DefaultsDescriptor) + origin = Origin.WebDefaults; + origin = Origin.WebXml; + } + + public OriginInfo (String n) + { + name = n; + origin = Origin.Annotation; + } + + public OriginInfo(String n, Origin o) + { + name = n; + origin = o; + } + + public String getName() + { + return name; + } + + public Origin getOriginType() + { + return origin; + } + + public Descriptor getDescriptor() + { + return descriptor; + } + } + + /** + * Ordering + * + * + */ + public interface Ordering + { + public List<Resource> order(List<Resource> fragments); + public boolean isAbsolute (); + public boolean hasOther(); + } + + /** + * AbsoluteOrdering + * + * An <absolute-order> element in web.xml + */ + public class AbsoluteOrdering implements Ordering + { + public static final String OTHER = "@@-OTHER-@@"; + protected List<String> _order = new ArrayList<String>(); + protected boolean _hasOther = false; + + /** + * Order the list of jars in WEB-INF/lib according to the ordering declarations in the descriptors + * @see org.eclipse.jetty.webapp.MetaData.Ordering#order(java.util.List) + */ + public List<Resource> order(List<Resource> jars) + { + List<Resource> orderedList = new ArrayList<Resource>(); + List<Resource> tmp = new ArrayList<Resource>(jars); + + //1. put everything into the list of named others, and take the named ones out of there, + //assuming we will want to use the <other> clause + Map<String,FragmentDescriptor> others = new HashMap(getNamedFragments()); + + //2. for each name, take out of the list of others, add to tail of list + int index = -1; + for (String item:_order) + { + if (!item.equals(OTHER)) + { + FragmentDescriptor f = others.remove(item); + if (f != null) + { + Resource jar = getJarForFragment(item); + orderedList.add(jar); //take from others and put into final list in order, ignoring duplicate names + //remove resource from list for resource matching name of descriptor + tmp.remove(jar); + } + } + else + index = orderedList.size(); //remember the index at which we want to add in all the others + } + + //3. if <other> was specified, insert rest of the fragments + if (_hasOther) + { + orderedList.addAll((index < 0? 0: index), tmp); + } + + return orderedList; + } + + public boolean isAbsolute() + { + return true; + } + + public void add (String name) + { + _order.add(name); + } + + public void addOthers () + { + if (_hasOther) + throw new IllegalStateException ("Duplicate <other> element in absolute ordering"); + + _hasOther = true; + _order.add(OTHER); + } + + public boolean hasOther () + { + return _hasOther; + } + } + + + /** + * RelativeOrdering + * + * A set of <order> elements in web-fragment.xmls. + */ + public class RelativeOrdering implements Ordering + { + protected LinkedList<Resource> _beforeOthers = new LinkedList<Resource>(); + protected LinkedList<Resource> _afterOthers = new LinkedList<Resource>(); + protected LinkedList<Resource> _noOthers = new LinkedList<Resource>(); + + /** + * Order the list of jars according to the ordering declared + * in the various web-fragment.xml files. + * @see org.eclipse.jetty.webapp.MetaData.Ordering#order(java.util.List) + */ + public List<Resource> order(List<Resource> jars) + { + //for each jar, put it into the ordering according to the fragment ordering + for (Resource jar:jars) + { + //check if the jar has a fragment descriptor + FragmentDescriptor descriptor = _webFragmentResourceMap.get(jar); + if (descriptor != null) + { + switch (descriptor.getOtherType()) + { + case None: + { + ((RelativeOrdering)_ordering).addNoOthers(jar); + break; + } + case Before: + { + ((RelativeOrdering)_ordering).addBeforeOthers(jar); + break; + } + case After: + { + ((RelativeOrdering)_ordering).addAfterOthers(jar); + break; + } + } + } + else + { + //jar fragment has no descriptor, but there is a relative ordering in place, so it must be part of the others + ((RelativeOrdering)_ordering).addNoOthers(jar); + } + } + + //now apply the ordering + List<Resource> orderedList = new ArrayList<Resource>(); + int maxIterations = 2; + boolean done = false; + do + { + //1. order the before-others according to any explicit before/after relationships + boolean changesBefore = orderList(_beforeOthers); + + //2. order the after-others according to any explicit before/after relationships + boolean changesAfter = orderList(_afterOthers); + + //3. order the no-others according to their explicit before/after relationships + boolean changesNone = orderList(_noOthers); + + //we're finished on a clean pass through with no ordering changes + done = (!changesBefore && !changesAfter && !changesNone); + } + while (!done && (--maxIterations >0)); + + //4. merge before-others + no-others +after-others + if (!done) + throw new IllegalStateException("Circular references for fragments"); + + for (Resource r: _beforeOthers) + orderedList.add(r); + for (Resource r: _noOthers) + orderedList.add(r); + for(Resource r: _afterOthers) + orderedList.add(r); + + return orderedList; + } + + public boolean isAbsolute () + { + return false; + } + + public boolean hasOther () + { + return !_beforeOthers.isEmpty() || !_afterOthers.isEmpty(); + } + + public void addBeforeOthers (Resource r) + { + _beforeOthers.addLast(r); + } + + public void addAfterOthers (Resource r) + { + _afterOthers.addLast(r); + } + + public void addNoOthers (Resource r) + { + _noOthers.addLast(r); + } + + protected boolean orderList (LinkedList<Resource> list) + { + //Take a copy of the list so we can iterate over it and at the same time do random insertions + boolean changes = false; + List<Resource> iterable = new ArrayList(list); + Iterator<Resource> itor = iterable.iterator(); + + while (itor.hasNext()) + { + Resource r = itor.next(); + FragmentDescriptor f = getFragment(r); + if (f == null) + { + //no fragment for this resource so cannot have any ordering directives + continue; + } + + //Handle any explicit <before> relationships for the fragment we're considering + List<String> befores = f.getBefores(); + if (befores != null && !befores.isEmpty()) + { + for (String b: befores) + { + //Fragment we're considering must be before b + //Check that we are already before it, if not, move us so that we are. + //If the name does not exist in our list, then get it out of the no-other list + if (!isBefore(list, f.getName(), b)) + { + //b is not already before name, move it so that it is + int idx1 = getIndexOf(list, f.getName()); + int idx2 = getIndexOf(list, b); + + //if b is not in the same list + if (idx2 < 0) + { + changes = true; + // must be in the noOthers list or it would have been an error + Resource bResource = getJarForFragment(b); + if (bResource != null) + { + //If its in the no-others list, insert into this list so that we are before it + if (_noOthers.remove(bResource)) + { + insert(list, idx1+1, b); + + } + } + } + else + { + //b is in the same list but b is before name, so swap it around + list.remove(idx1); + insert(list, idx2, f.getName()); + changes = true; + } + } + } + } + + //Handle any explicit <after> relationships + List<String> afters = f.getAfters(); + if (afters != null && !afters.isEmpty()) + { + for (String a: afters) + { + //Check that fragment we're considering is after a, moving it if possible if its not + if (!isAfter(list, f.getName(), a)) + { + //name is not after a, move it + int idx1 = getIndexOf(list, f.getName()); + int idx2 = getIndexOf(list, a); + + //if a is not in the same list as name + if (idx2 < 0) + { + changes = true; + //take it out of the noOthers list and put it in the right place in this list + Resource aResource = getJarForFragment(a); + if (aResource != null) + { + if (_noOthers.remove(aResource)) + { + insert(list,idx1, aResource); + } + } + } + else + { + //a is in the same list as name, but in the wrong place, so move it + list.remove(idx2); + insert(list,idx1, a); + changes = true; + } + } + //Name we're considering must be after this name + //Check we're already after it, if not, move us so that we are. + //If the name does not exist in our list, then get it out of the no-other list + } + } + } + + return changes; + } + + /** + * Is fragment with name a before fragment with name b? + * @param list + * @param fragNameA + * @param fragNameB + * @return + */ + protected boolean isBefore (List<Resource> list, String fragNameA, String fragNameB) + { + //check if a and b are already in the same list, and b is already + //before a + int idxa = getIndexOf(list, fragNameA); + int idxb = getIndexOf(list, fragNameB); + + + if (idxb >=0 && idxb < idxa) + { + //a and b are in the same list but a is not before b + return false; + } + + if (idxb < 0) + { + //a and b are not in the same list, but it is still possible that a is before + //b, depending on which list we're examining + if (list == _beforeOthers) + { + //The list we're looking at is the beforeOthers.If b is in the _afterOthers or the _noOthers, then by + //definition a is before it + return true; + } + else if (list == _afterOthers) + { + //The list we're looking at is the afterOthers, then a will be the tail of + //the final list. If b is in the beforeOthers list, then b will be before a and an error. + if (_beforeOthers.contains(fragNameB)) + throw new IllegalStateException("Incorrect relationship: "+fragNameA+" before "+fragNameB); + else + return false; //b could be moved to the list + } + } + + //a and b are in the same list and a is already before b + return true; + } + + + /** + * Is fragment name "a" after fragment name "b"? + * @param list + * @param fragNameA + * @param fragNameB + * @return + */ + protected boolean isAfter(List<Resource> list, String fragNameA, String fragNameB) + { + int idxa = getIndexOf(list, fragNameA); + int idxb = getIndexOf(list, fragNameB); + + if (idxb >=0 && idxa < idxb) + { + //a and b are both in the same list, but a is before b + return false; + } + + if (idxb < 0) + { + //a and b are in different lists. a could still be after b depending on which list it is in. + + if (list == _afterOthers) + { + //The list we're looking at is the afterOthers. If b is in the beforeOthers or noOthers then + //by definition a is after b because a is in the afterOthers list. + return true; + } + else if (list == _beforeOthers) + { + //The list we're looking at is beforeOthers, and contains a and will be before + //everything else in the final ist. If b is in the afterOthers list, then a cannot be before b. + if (_afterOthers.contains(fragNameB)) + throw new IllegalStateException("Incorrect relationship: "+fragNameB+" after "+fragNameA); + else + return false; //b could be moved from noOthers list + } + } + + return true; //a and b in the same list, a is after b + } + + /** + * Insert the resource matching the fragName into the list of resources + * at the location indicated by index. + * + * @param list + * @param index + * @param fragName + */ + protected void insert(List<Resource> list, int index, String fragName) + { + Resource jar = getJarForFragment(fragName); + if (jar == null) + throw new IllegalStateException("No jar for insertion"); + + insert(list, index, jar); + } + + protected void insert(List<Resource> list, int index, Resource resource) + { + if (list == null) + throw new IllegalStateException("List is null for insertion"); + + //add it at the end + if (index > list.size()) + list.add(resource); + else + list.add(index, resource); + } + + protected void remove (List<Resource> resources, Resource r) + { + if (resources == null) + return; + resources.remove(r); + } + + protected int getIndexOf(List<Resource> resources, String fragmentName) + { + FragmentDescriptor fd = getFragment(fragmentName); + if (fd == null) + return -1; + + + Resource r = getJarForFragment(fragmentName); + if (r == null) + return -1; + + return resources.indexOf(r); + } + } + + + + public MetaData (WebAppContext context) throws ClassNotFoundException + { + _context = context; + + } + + public WebAppContext getContext() + { + return _context; + } + + + + public void setDefaults (Resource webDefaults) + throws Exception + { + _webDefaultsRoot = new DefaultsDescriptor(webDefaults, this); + _webDefaultsRoot.parse(); + if (_webDefaultsRoot.isOrdered()) + { + if (_ordering == null) + _ordering = new AbsoluteOrdering(); + + List<String> order = _webDefaultsRoot.getOrdering(); + for (String s:order) + { + if (s.equalsIgnoreCase("others")) + ((AbsoluteOrdering)_ordering).addOthers(); + else + ((AbsoluteOrdering)_ordering).add(s); + } + } + } + + public void setWebXml (Resource webXml) + throws Exception + { + _webXmlRoot = new Descriptor(webXml, this); + _webXmlRoot.parse(); + if (_webXmlRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.True) + _context.setAttribute(METADATA_COMPLETE, Boolean.TRUE); + else + _context.setAttribute(METADATA_COMPLETE, Boolean.FALSE); + + _context.setAttribute(WEBXML_CLASSNAMES, _webXmlRoot.getClassNames()); + + if (_webXmlRoot.isOrdered()) + { + if (_ordering == null) + _ordering = new AbsoluteOrdering(); + + List<String> order = _webXmlRoot.getOrdering(); + for (String s:order) + { + if (s.equalsIgnoreCase("others")) + ((AbsoluteOrdering)_ordering).addOthers(); + else + ((AbsoluteOrdering)_ordering).add(s); + } + } + } + + public void setOverride (Resource override) + throws Exception + { + _webOverrideRoot = new OverrideDescriptor(override, this); + _webOverrideRoot.setValidating(false); + _webOverrideRoot.parse(); + if (_webOverrideRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.True) + _context.setAttribute(METADATA_COMPLETE, Boolean.TRUE); + else if (_webOverrideRoot.getMetaDataComplete() == Descriptor.MetaDataComplete.False) + _context.setAttribute(METADATA_COMPLETE, Boolean.FALSE); + + if (_webOverrideRoot.isOrdered()) + { + if (_ordering == null) + _ordering = new AbsoluteOrdering(); + + List<String> order = _webOverrideRoot.getOrdering(); + for (String s:order) + { + if (s.equalsIgnoreCase("others")) + ((AbsoluteOrdering)_ordering).addOthers(); + else + ((AbsoluteOrdering)_ordering).add(s); + } + } + } + + + /** + * Add a web-fragment.xml + * + * @param jarResource the jar the fragment is contained in + * @param xmlResource the resource representing the xml file + * @throws Exception + */ + public void addFragment (Resource jarResource, Resource xmlResource) + throws Exception + { + Boolean metaComplete = (Boolean)_context.getAttribute(METADATA_COMPLETE); + if (metaComplete != null && metaComplete.booleanValue()) + return; //do not process anything else if web.xml/web-override.xml set metadata-complete + + //Metadata-complete is not set, or there is no web.xml + FragmentDescriptor descriptor = new FragmentDescriptor(xmlResource, this); + _webFragmentResourceMap.put(jarResource, descriptor); + _webFragmentRoots.add(descriptor); + + descriptor.parse(); + + if (descriptor.getName() != null) + _webFragmentNameMap.put(descriptor.getName(), descriptor); + + //If web.xml has specified an absolute ordering, ignore any relative ordering in the fragment + if (_ordering != null && _ordering.isAbsolute()) + return; + + if (_ordering == null && descriptor.isOrdered()) + _ordering = new RelativeOrdering(); + } + + /** + * Annotations not associated with a WEB-INF/lib fragment jar. + * These are from WEB-INF/classes or the ??container path?? + * @param annotations + */ + public void addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations) + { + _annotations.addAll(annotations); + } + + public void addDiscoveredAnnotations(Resource resource, List<DiscoveredAnnotation> annotations) + { + _webFragmentAnnotations.put(resource, new ArrayList<DiscoveredAnnotation>(annotations)); + } + + public void addDescriptorProcessor(DescriptorProcessor p) + { + _descriptorProcessors.add(p); + } + + public void orderFragments () + { + //if we have already ordered them don't do it again + if (_orderedResources != null) + return; + + if (_ordering != null) + { + //Get the jars in WEB-INF/lib according to the order specified + _orderedResources = _ordering.order((List<Resource>)_context.getAttribute(WebInfConfiguration.WEB_INF_JAR_RESOURCES)); + + _context.setAttribute(WebInfConfiguration.WEB_INF_ORDERED_JAR_RESOURCES, _orderedResources); + List<String> orderedJars = new ArrayList<String>(); + + for (Resource webInfJar:_orderedResources) + { + //get just the name of the jar file + String fullname = webInfJar.getName(); + int i = fullname.indexOf(".jar"); + int j = fullname.lastIndexOf("/", i); + orderedJars.add(fullname.substring(j+1,i+4)); + } + + _context.setAttribute(ORDERED_LIBS, orderedJars); + } + else + _orderedResources = new ArrayList<Resource>((List<Resource>)_context.getAttribute(WebInfConfiguration.WEB_INF_JAR_RESOURCES)); + } + + + /** + * Resolve all servlet/filter/listener metadata from all sources: descriptors and annotations. + * + */ + public void resolve () + throws Exception + { + //TODO - apply all descriptors and annotations in order: + //apply descriptorProcessors to web-defaults.xml + //apply descriptorProcessors to web.xml + //apply descriptorProcessors to web-override.xml + //apply discovered annotations from container path + //apply discovered annotations from WEB-INF/classes + //for the ordering of the jars in WEB-INF/lib: + // +apply descriptorProcessors to web-fragment.xml + // +apply discovered annotations + + for (DescriptorProcessor p:_descriptorProcessors) + { + p.process(getWebDefault()); + p.process(getWebXml()); + p.process(getOverrideWeb()); + } + + for (DiscoveredAnnotation a:_annotations) + a.apply(); + + + List<Resource> resources = getOrderedResources(); + for (Resource r:resources) + { + FragmentDescriptor fd = _webFragmentResourceMap.get(r); + if (fd != null) + { + for (DescriptorProcessor p:_descriptorProcessors) + { + p.process(fd); + } + } + + List<DiscoveredAnnotation> fragAnnotations = _webFragmentAnnotations.get(r); + if (fragAnnotations != null) + { + for (DiscoveredAnnotation a:fragAnnotations) + a.apply(); + } + } + } + + public boolean isDistributable () + { + boolean distributable = ( + (_webDefaultsRoot != null && _webDefaultsRoot.isDistributable()) + || (_webXmlRoot != null && _webXmlRoot.isDistributable()) + || (_webOverrideRoot != null && _webOverrideRoot.isDistributable())); + + List<Resource> orderedResources = getOrderedResources(); + for (Resource r: orderedResources) + { + FragmentDescriptor d = _webFragmentResourceMap.get(r); + if (d!=null) + distributable = distributable && d.isDistributable(); + } + return distributable; + } + + + public Descriptor getWebXml () + { + return _webXmlRoot; + } + + public Descriptor getOverrideWeb () + { + return _webOverrideRoot; + } + + public Descriptor getWebDefault () + { + return _webDefaultsRoot; + } + + public List<FragmentDescriptor> getFragments () + { + return _webFragmentRoots; + } + + public List<Resource> getOrderedResources () + { + return _orderedResources; + } + + public List<FragmentDescriptor> getOrderedFragments () + { + List<FragmentDescriptor> list = new ArrayList<FragmentDescriptor>(); + if (_orderedResources == null) + return list; + + for (Resource r:_orderedResources) + { + FragmentDescriptor fd = _webFragmentResourceMap.get(r); + if (fd != null) + list.add(fd); + } + return list; + } + + public Ordering getOrdering() + { + return _ordering; + } + + public void setOrdering (Ordering o) + { + _ordering = o; + } + + public FragmentDescriptor getFragment (Resource jar) + { + return _webFragmentResourceMap.get(jar); + } + + public FragmentDescriptor getFragment(String name) + { + return _webFragmentNameMap.get(name); + } + + public Resource getJarForFragment (String name) + { + FragmentDescriptor f = getFragment(name); + if (f == null) + return null; + + Resource jar = null; + for (Resource r: _webFragmentResourceMap.keySet()) + { + if (_webFragmentResourceMap.get(r).equals(f)) + jar = r; + } + return jar; + } + + public Map<String,FragmentDescriptor> getNamedFragments () + { + return Collections.unmodifiableMap(_webFragmentNameMap); + } + + + public Origin getOrigin (String name) + { + OriginInfo x = _origins.get(name); + if (x == null) + return Origin.NotSet; + + return x.getOriginType(); + } + + + public Descriptor getOriginDescriptor (String name) + { + OriginInfo o = _origins.get(name); + if (o == null) + return null; + return o.getDescriptor(); + } + + public void setOrigin (String name, Descriptor d) + { + OriginInfo x = new OriginInfo (name, d); + _origins.put(name, x); + } + + public void setOrigin (String name) + { + if (name == null) + return; + + OriginInfo x = new OriginInfo (name, Origin.Annotation); + _origins.put(name, x); + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/OverrideDescriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/OverrideDescriptor.java new file mode 100644 index 0000000000..fe7adb3599 --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/OverrideDescriptor.java @@ -0,0 +1,29 @@ +// ======================================================================== +// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import org.eclipse.jetty.util.resource.Resource; + +/** + * OverrideDescriptor + * + * + */ +public class OverrideDescriptor extends Descriptor +{ + public OverrideDescriptor(Resource xml, MetaData processor) + { + super(xml, processor); + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java new file mode 100644 index 0000000000..952f8da4ee --- /dev/null +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java @@ -0,0 +1,1335 @@ +// ======================================================================== +// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.EventListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jetty.server.DispatcherType; +import javax.servlet.ServletException; +import org.eclipse.jetty.servlet.api.ServletRegistration; + + +import org.eclipse.jetty.http.security.Constraint; +import org.eclipse.jetty.security.ConstraintAware; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.SecurityHandler; +import org.eclipse.jetty.security.authentication.FormAuthenticator; +import org.eclipse.jetty.servlet.ErrorPageErrorHandler; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; +import org.eclipse.jetty.servlet.Holder; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; +import org.eclipse.jetty.util.LazyList; +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.MetaData.Origin; +import org.eclipse.jetty.xml.XmlParser; + +/** + * StandardDescriptorProcessor + * + * + */ +public class StandardDescriptorProcessor extends IterativeDescriptorProcessor +{ + public static final String STANDARD_PROCESSOR = "org.eclipse.jetty.standardDescriptorProcessor"; + protected WebAppContext _context; + + //the shared configuration operated on by web-default.xml, web.xml, web-override.xml and all web-fragment.xml + protected ServletHandler _servletHandler; + protected SecurityHandler _securityHandler; + protected Object _filters; + protected Object _filterMappings; + protected Object _servlets; + protected Object _servletMappings; + protected Object _listeners; + protected Object _listenerClassNames; + protected Object _welcomeFiles; + protected Set<String> _roles = new HashSet<String>(); + protected List<ConstraintMapping> _constraintMappings = new ArrayList<ConstraintMapping>(); + protected Map _errorPages; + protected boolean _hasJSP; + protected String _jspServletName; + protected String _jspServletClass; + protected boolean _defaultWelcomeFileList; + protected MetaData _metaData; + + + + public StandardDescriptorProcessor () + { + + try + { + registerVisitor("context-param", this.getClass().getDeclaredMethod("visitContextParam", __signature)); + registerVisitor("display-name", this.getClass().getDeclaredMethod("visitDisplayName", __signature)); + registerVisitor("servlet", this.getClass().getDeclaredMethod("visitServlet", __signature)); + registerVisitor("servlet-mapping", this.getClass().getDeclaredMethod("visitServletMapping", __signature)); + registerVisitor("session-config", this.getClass().getDeclaredMethod("visitSessionConfig", __signature)); + registerVisitor("mime-mapping", this.getClass().getDeclaredMethod("visitMimeMapping", __signature)); + registerVisitor("welcome-file-list", this.getClass().getDeclaredMethod("visitWelcomeFileList", __signature)); + registerVisitor("locale-encoding-mapping-list", this.getClass().getDeclaredMethod("visitLocaleEncodingList", __signature)); + registerVisitor("error-page", this.getClass().getDeclaredMethod("visitErrorPage", __signature)); + registerVisitor("taglib", this.getClass().getDeclaredMethod("visitTagLib", __signature)); + registerVisitor("jsp-config", this.getClass().getDeclaredMethod("visitJspConfig", __signature)); + registerVisitor("security-constraint", this.getClass().getDeclaredMethod("visitSecurityConstraint", __signature)); + registerVisitor("login-config", this.getClass().getDeclaredMethod("visitLoginConfig", __signature)); + registerVisitor("security-role", this.getClass().getDeclaredMethod("visitSecurityRole", __signature)); + registerVisitor("filter", this.getClass().getDeclaredMethod("visitFilter", __signature)); + registerVisitor("filter-mapping", this.getClass().getDeclaredMethod("visitFilterMapping", __signature)); + registerVisitor("listener", this.getClass().getDeclaredMethod("visitListener", __signature)); + registerVisitor("distributable", this.getClass().getDeclaredMethod("visitDistributable", __signature)); + } + catch (Exception e) + { + throw new IllegalStateException(e); + } + } + + + + /** + * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#start() + */ + public void start(Descriptor descriptor) + { + _metaData = descriptor.getMetaData(); + _context = _metaData.getContext(); + + //Get the current objects from the context + _servletHandler = _context.getServletHandler(); + _securityHandler = (SecurityHandler)_context.getSecurityHandler(); + _filters = LazyList.array2List(_servletHandler.getFilters()); + _filterMappings = LazyList.array2List(_servletHandler.getFilterMappings()); + _servlets = LazyList.array2List(_servletHandler.getServlets()); + _servletMappings = LazyList.array2List(_servletHandler.getServletMappings()); + _listeners = LazyList.array2List(_context.getEventListeners()); + _welcomeFiles = LazyList.array2List(_context.getWelcomeFiles()); + if (_securityHandler instanceof ConstraintAware) + { + _constraintMappings.addAll(((ConstraintAware) _securityHandler).getConstraintMappings()); + if (((ConstraintAware) _securityHandler).getRoles() != null) + { + _roles.addAll(((ConstraintAware) _securityHandler).getRoles()); + } + } + _errorPages = _context.getErrorHandler() instanceof ErrorPageErrorHandler ? ((ErrorPageErrorHandler)_context.getErrorHandler()).getErrorPages() : null; + } + + + + /** + * @see org.eclipse.jetty.webapp.IterativeDescriptorProcessor#end() + */ + public void end(Descriptor descriptor) + { + //Set the context with the results of the processing + _servletHandler.setFilters((FilterHolder[]) LazyList.toArray(_filters, FilterHolder.class)); + _servletHandler.setFilterMappings((FilterMapping[]) LazyList.toArray(_filterMappings, FilterMapping.class)); + _servletHandler.setServlets((ServletHolder[]) LazyList.toArray(_servlets, ServletHolder.class)); + _servletHandler.setServletMappings((ServletMapping[]) LazyList.toArray(_servletMappings, ServletMapping.class)); + _context.setEventListeners((EventListener[]) LazyList.toArray(_listeners, EventListener.class)); + _context.setWelcomeFiles((String[]) LazyList.toArray(_welcomeFiles, String.class)); + // TODO jaspi check this + if (_securityHandler instanceof ConstraintAware) + { + for (ConstraintMapping m:_constraintMappings) + ((ConstraintAware) _securityHandler).addConstraintMapping(m); + for (String r:_roles) + ((ConstraintAware) _securityHandler).addRole(r); + } + + if (_errorPages != null && _context.getErrorHandler() instanceof ErrorPageErrorHandler) + ((ErrorPageErrorHandler)_context.getErrorHandler()).setErrorPages(_errorPages); + + _roles.clear(); + _constraintMappings.clear(); + _metaData = null; + _context = null; + } + + public void visitContextParam (Descriptor descriptor, XmlParser.Node node) + { + String name = node.getString("param-name", false, true); + String value = node.getString("param-value", false, true); + Origin o = _metaData.getOrigin("context-param."+name); + switch (o) + { + case NotSet: + { + //just set it + _context.getInitParams().put(name, value); + _metaData.setOrigin("context-param."+name, descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //previously set by a web xml, allow other web xml files to override + if (!(descriptor instanceof FragmentDescriptor)) + { + _context.getInitParams().put(name, value); + _metaData.setOrigin("context-param."+name, descriptor); + } + break; + } + case WebFragment: + { + //previously set by a web-fragment, this fragment's value must be the same + if (descriptor instanceof FragmentDescriptor) + { + if (!((String)_context.getInitParams().get(name)).equals(value)) + throw new IllegalStateException("Conflicting context-param "+name+"="+value+" in "+descriptor.getResource()); + } + break; + } + } + if (Log.isDebugEnabled()) Log.debug("ContextParam: " + name + "=" + value); + + } + + + /* ------------------------------------------------------------ */ + protected void visitDisplayName(Descriptor descriptor, XmlParser.Node node) + { + //Servlet Spec 3.0 p. 74 Ignore from web-fragments + if (!(descriptor instanceof FragmentDescriptor)) + { + _context.setDisplayName(node.toString(false, true)); + _metaData.setOrigin("display-name", descriptor); + } + } + + protected void visitServlet(Descriptor descriptor, XmlParser.Node node) + { + String id = node.getAttribute("id"); + + // initialize holder + String servlet_name = node.getString("servlet-name", false, true); + ServletHolder holder = _servletHandler.getServlet(servlet_name); + + /* + * If servlet of that name does not already exist, create it. + */ + if (holder == null) + { + holder = _servletHandler.newServletHolder(); + holder.setName(servlet_name); + _servlets = LazyList.add(_servlets, holder); + } + ServletRegistration.Dynamic registration = holder.getRegistration(); + + // init params + Iterator iParamsIter = node.iterator("init-param"); + while (iParamsIter.hasNext()) + { + XmlParser.Node paramNode = (XmlParser.Node) iParamsIter.next(); + String pname = paramNode.getString("param-name", false, true); + String pvalue = paramNode.getString("param-value", false, true); + + Origin origin = _metaData.getOrigin(servlet_name+".servlet.init-param."+pname); + + switch (origin) + { + case NotSet: + { + //init-param not already set, so set it + + registration.setInitParameter(pname, pvalue); + _metaData.setOrigin(servlet_name+".servlet.init-param."+pname, descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //previously set by a web xml descriptor, if we're parsing another web xml descriptor allow override + //otherwise just ignore it + if (!(descriptor instanceof FragmentDescriptor)) + { + registration.setInitParameter(pname, pvalue); + _metaData.setOrigin(servlet_name+".servlet.init-param."+pname, descriptor); + } + break; + } + case WebFragment: + { + //previously set by a web-fragment, make sure that the value matches, otherwise its an error + if (!registration.getInitParameter(pname).equals(pvalue)) + throw new IllegalStateException("Mismatching init-param "+pname+"="+pvalue+" in "+descriptor.getResource()); + break; + } + } + } + + String servlet_class = node.getString("servlet-class", false, true); + + // Handle JSP + if (id != null && id.equals("jsp")) + { + _jspServletName = servlet_name; + _jspServletClass = servlet_class; + try + { + Loader.loadClass(this.getClass(), servlet_class); + _hasJSP = true; + } + catch (ClassNotFoundException e) + { + Log.info("NO JSP Support for {}, did not find {}", _context.getContextPath(), servlet_class); + _hasJSP = false; + _jspServletClass = servlet_class = "org.eclipse.jetty.servlet.NoJspServlet"; + } + if (registration.getInitParameter("scratchdir") == null) + { + File tmp = _context.getTempDirectory(); + File scratch = new File(tmp, "jsp"); + if (!scratch.exists()) scratch.mkdir(); + registration.setInitParameter("scratchdir", scratch.getAbsolutePath()); + + if ("?".equals(registration.getInitParameter("classpath"))) + { + String classpath = _context.getClassPath(); + Log.debug("classpath=" + classpath); + if (classpath != null) + registration.setInitParameter("classpath", classpath); + } + } + + /* Set the webapp's classpath for Jasper */ + _context.setAttribute("org.apache.catalina.jsp_classpath", _context.getClassPath()); + /* Set the system classpath for Jasper */ + registration.setInitParameter("com.sun.appserv.jsp.classpath", getSystemClassPath()); + } + + //Set the servlet-class + if (servlet_class != null) + { + descriptor.addClassName(servlet_class); + + Origin o = _metaData.getOrigin(servlet_name+".servlet.servlet-class"); + switch (o) + { + case NotSet: + { + //the class of the servlet has not previously been set, so set it + holder.setClassName(servlet_class); + _metaData.setOrigin(servlet_name+".servlet.servlet-class", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //the class of the servlet was set by a web xml file, only allow web-override/web-default to change it + if (!(descriptor instanceof FragmentDescriptor)) + { + holder.setClassName(servlet_class); + _metaData.setOrigin(servlet_name+".servlet.servlet-class", descriptor); + } + break; + } + case WebFragment: + { + //the class was set by another fragment, ensure this fragment's value is the same + if (!servlet_class.equals(holder.getClassName())) + throw new IllegalStateException("Conflicting servlet-class "+servlet_class+" in "+descriptor.getResource()); + break; + } + } + } + + // Handler JSP file + String jsp_file = node.getString("jsp-file", false, true); + if (jsp_file != null) + { + holder.setForcedPath(jsp_file); + holder.setClassName(_jspServletClass); + } + + // handle load-on-startup + XmlParser.Node startup = node.get("load-on-startup"); + if (startup != null) + { + String s = startup.toString(false, true).toLowerCase(); + int order = 0; + if (s.startsWith("t")) + { + Log.warn("Deprecated boolean load-on-startup. Please use integer"); + order = 1; + } + else + { + try + { + if (s != null && s.trim().length() > 0) order = Integer.parseInt(s); + } + catch (Exception e) + { + Log.warn("Cannot parse load-on-startup " + s + ". Please use integer"); + Log.ignore(e); + } + } + + Origin o = _metaData.getOrigin(servlet_name+".servlet.load-on-startup"); + switch (o) + { + case NotSet: + { + //not already set, so set it now + registration.setLoadOnStartup(order); + _metaData.setOrigin(servlet_name+".servlet.load-on-startup", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //if it was already set by a web xml descriptor and we're parsing another web xml descriptor, then override it + if (!(descriptor instanceof FragmentDescriptor)) + { + registration.setLoadOnStartup(order); + _metaData.setOrigin(servlet_name+".servlet.load-on-startup", descriptor); + } + break; + } + case WebFragment: + { + //it was already set by another fragment, if we're parsing a fragment, the values must match + if (order != holder.getInitOrder()) + throw new IllegalStateException("Conflicting load-on-startup value in "+descriptor.getResource()); + break; + } + } + } + + Iterator sRefsIter = node.iterator("security-role-ref"); + while (sRefsIter.hasNext()) + { + XmlParser.Node securityRef = (XmlParser.Node) sRefsIter.next(); + String roleName = securityRef.getString("role-name", false, true); + String roleLink = securityRef.getString("role-link", false, true); + if (roleName != null && roleName.length() > 0 && roleLink != null && roleLink.length() > 0) + { + if (Log.isDebugEnabled()) Log.debug("link role " + roleName + " to " + roleLink + " for " + this); + Origin o = _metaData.getOrigin(servlet_name+".servlet.role-name."+roleName); + switch (o) + { + case NotSet: + { + //set it + holder.setUserRoleLink(roleName, roleLink); + _metaData.setOrigin(servlet_name+".servlet.role-name."+roleName, descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //only another web xml descriptor (web-default,web-override web.xml) can override an already set value + if (!(descriptor instanceof FragmentDescriptor)) + { + holder.setUserRoleLink(roleName, roleLink); + _metaData.setOrigin(servlet_name+".servlet.role-name."+roleName, descriptor); + } + break; + } + case WebFragment: + { + if (!holder.getUserRoleLink(roleName).equals(roleLink)) + throw new IllegalStateException("Conflicting role-link for role-name "+roleName+" for servlet "+servlet_name+" in "+descriptor.getResource()); + break; + } + } + } + else + { + Log.warn("Ignored invalid security-role-ref element: " + "servlet-name=" + holder.getName() + ", " + securityRef); + } + } + + + XmlParser.Node run_as = node.get("run-as"); + if (run_as != null) + { + String roleName = run_as.getString("role-name", false, true); + + if (roleName != null) + { + Origin o = _metaData.getOrigin(servlet_name+".servlet.run-as"); + switch (o) + { + case NotSet: + { + //run-as not set, so set it + registration.setRunAsRole(roleName); + _metaData.setOrigin(servlet_name+".servlet.run-as", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //run-as was set by a web xml, only allow it to be changed if we're currently parsing another web xml(override/default) + if (!(descriptor instanceof FragmentDescriptor)) + { + registration.setRunAsRole(roleName); + _metaData.setOrigin(servlet_name+".servlet.run-as", descriptor); + } + break; + } + case WebFragment: + { + //run-as was set by another fragment, this fragment must show the same value + if (!registration.getRunAsRole().equals(roleName)) + throw new IllegalStateException("Conflicting run-as role "+roleName+" for servlet "+servlet_name+" in "+descriptor.getResource()); + break; + } + } + } + } + } + + protected void visitServletMapping(Descriptor descriptor, XmlParser.Node node) + { + //Servlet Spec 3.0, p74 + //servlet-mappings are always additive, whether from web xml descriptors (web.xml/web-default.xml/web-override.xml) or web-fragments. + String servlet_name = node.getString("servlet-name", false, true); + ServletMapping mapping = new ServletMapping(); + mapping.setServletName(servlet_name); + + if (_metaData.getOrigin(servlet_name+".servlet.mappings") == Origin.NotSet) + _metaData.setOrigin(servlet_name+".servlet.mappings", descriptor); + + ArrayList paths = new ArrayList(); + Iterator iter = node.iterator("url-pattern"); + while (iter.hasNext()) + { + String p = ((XmlParser.Node) iter.next()).toString(false, true); + p = normalizePattern(p); + paths.add(p); + } + mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()])); + _servletMappings = LazyList.add(_servletMappings, mapping); + } + + + protected void visitSessionConfig(Descriptor descriptor, XmlParser.Node node) + { + XmlParser.Node tNode = node.get("session-timeout"); + if (tNode != null) + { + int timeout = Integer.parseInt(tNode.toString(false, true)); + _context.getSessionHandler().getSessionManager().setMaxInactiveInterval(timeout * 60); + } + } + + protected void visitMimeMapping(Descriptor descriptor, XmlParser.Node node) + { + String extension = node.getString("extension", false, true); + if (extension != null && extension.startsWith(".")) + extension = extension.substring(1); + String mimeType = node.getString("mime-type", false, true); + if (extension != null) + { + Origin o = _metaData.getOrigin("extension."+extension); + switch (o) + { + case NotSet: + { + //no mime-type set for the extension yet + _context.getMimeTypes().addMimeMapping(extension, mimeType); + _metaData.setOrigin("extension."+extension, descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //a mime-type was set for the extension in a web xml, only allow web-default/web-override to change + if (!(descriptor instanceof FragmentDescriptor)) + { + _context.getMimeTypes().addMimeMapping(extension, mimeType); + _metaData.setOrigin("extension."+extension, descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment set the value, all web-fragments must have the same value + if (!_context.getMimeTypes().getMimeByExtension("."+extension).equals(_context.getMimeTypes().CACHE.lookup(mimeType))) + throw new IllegalStateException("Conflicting mime-type "+mimeType+" for extension "+extension+" in "+descriptor.getResource()); + break; + } + } + } + } + + protected void visitWelcomeFileList(Descriptor descriptor, XmlParser.Node node) + { + Origin o = _metaData.getOrigin("welcome-file-list"); + switch (o) + { + case NotSet: + { + _metaData.setOrigin("welcome-file-list", descriptor); + addWelcomeFiles(node); + break; + } + case WebXml: + { + //web.xml set the welcome-file-list, all other descriptors then just merge in + addWelcomeFiles(node); + break; + } + case WebDefaults: + { + //if web-defaults set the welcome-file-list first and + //we're processing web.xml then reset the welcome-file-list + if (!(descriptor instanceof DefaultsDescriptor) && !(descriptor instanceof OverrideDescriptor) && !(descriptor instanceof FragmentDescriptor)) + { + _welcomeFiles = null; + } + addWelcomeFiles(node); + break; + } + case WebOverride: + { + //web-override set the list, all other descriptors just merge in + addWelcomeFiles(node); + break; + } + case WebFragment: + { + //A web-fragment first set the welcome-file-list. Other descriptors just add. + addWelcomeFiles(node); + break; + } + } + } + + protected void visitLocaleEncodingList(Descriptor descriptor, XmlParser.Node node) + { + Iterator iter = node.iterator("locale-encoding-mapping"); + while (iter.hasNext()) + { + XmlParser.Node mapping = (XmlParser.Node) iter.next(); + String locale = mapping.getString("locale", false, true); + String encoding = mapping.getString("encoding", false, true); + + if (encoding != null) + { + Origin o = _metaData.getOrigin("locale-encoding."+locale); + switch (o) + { + case NotSet: + { + //no mapping for the locale yet, so set it + _context.addLocaleEncoding(locale, encoding); + _metaData.setOrigin("locale-encoding."+locale, descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //a value was set in a web descriptor, only allow another web descriptor to change it (web-default/web-override) + if (!(descriptor instanceof FragmentDescriptor)) + { + _context.addLocaleEncoding(locale, encoding); + _metaData.setOrigin("locale-encoding."+locale, descriptor); + } + break; + } + case WebFragment: + { + //a value was set by a web-fragment, all fragments must have the same value + if (!encoding.equals(_context.getLocaleEncoding(locale))) + throw new IllegalStateException("Conflicting locale-encoding mapping for locale "+locale+" in "+descriptor.getResource()); + break; + } + } + } + } + } + + protected void visitErrorPage(Descriptor descriptor, XmlParser.Node node) + { + String error = node.getString("error-code", false, true); + if (error == null || error.length() == 0) error = node.getString("exception-type", false, true); + String location = node.getString("location", false, true); + + if (_errorPages == null) + _errorPages = new HashMap(); + + Origin o = _metaData.getOrigin("error."+error); + switch (o) + { + case NotSet: + { + //no error page setup for this code or exception yet + _errorPages.put(error, location); + _metaData.setOrigin("error."+error, descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //an error page setup was set in web.xml, only allow other web xml descriptors to override it + if (!(descriptor instanceof FragmentDescriptor)) + { + _errorPages.put(error, location); + _metaData.setOrigin("error."+error, descriptor); + } + break; + } + case WebFragment: + { + //another web fragment set the same error code or exception, if its different its an error + if (!_errorPages.get(error).equals(location)) + throw new IllegalStateException("Conflicting error-code or exception-type "+error+" in "+descriptor.getResource()); + break; + } + } + + } + + protected void addWelcomeFiles (XmlParser.Node node) + { + Iterator iter = node.iterator("welcome-file"); + while (iter.hasNext()) + { + XmlParser.Node indexNode = (XmlParser.Node) iter.next(); + String welcome = indexNode.toString(false, true); + + //Servlet Spec 3.0 p. 74 welcome files are additive + _welcomeFiles = LazyList.add(_welcomeFiles, welcome); + } + } + + protected void visitTagLib(Descriptor descriptor, XmlParser.Node node) + { + //Additive across web.xml and web-fragment.xml + String uri = node.getString("taglib-uri", false, true); + String location = node.getString("taglib-location", false, true); + + _context.setResourceAlias(uri, location); + } + + protected void visitJspConfig(Descriptor descriptor, XmlParser.Node node) + { + for (int i = 0; i < node.size(); i++) + { + Object o = node.get(i); + if (o instanceof XmlParser.Node && "taglib".equals(((XmlParser.Node) o).getTag())) + visitTagLib(descriptor, (XmlParser.Node) o); + } + + // Map URLs from jsp property groups to JSP servlet. + // this is more JSP stupidness creaping into the servlet spec + Iterator iter = node.iterator("jsp-property-group"); + Object paths = null; + while (iter.hasNext()) + { + XmlParser.Node group = (XmlParser.Node) iter.next(); + Iterator iter2 = group.iterator("url-pattern"); + while (iter2.hasNext()) + { + String url = ((XmlParser.Node) iter2.next()).toString(false, true); + url = normalizePattern(url); + paths = LazyList.add(paths, url); + } + } + + if (LazyList.size(paths) > 0) + { + String jspName = getJSPServletName(); + if (jspName != null) + { + ServletMapping mapping = new ServletMapping(); + mapping.setServletName(jspName); + mapping.setPathSpecs(LazyList.toStringArray(paths)); + _servletMappings = LazyList.add(_servletMappings, mapping); + } + } + } + + protected void visitSecurityConstraint(Descriptor descriptor, XmlParser.Node node) + { + Constraint scBase = new Constraint(); + + //ServletSpec 3.0, p74 security-constraints, as minOccurs > 1, are additive + //across fragments + try + { + XmlParser.Node auths = node.get("auth-constraint"); + + if (auths != null) + { + scBase.setAuthenticate(true); + // auth-constraint + Iterator iter = auths.iterator("role-name"); + Object roles = null; + while (iter.hasNext()) + { + String role = ((XmlParser.Node) iter.next()).toString(false, true); + roles = LazyList.add(roles, role); + } + scBase.setRoles(LazyList.toStringArray(roles)); + } + + XmlParser.Node data = node.get("user-data-constraint"); + if (data != null) + { + data = data.get("transport-guarantee"); + String guarantee = data.toString(false, true).toUpperCase(); + if (guarantee == null || guarantee.length() == 0 || "NONE".equals(guarantee)) + scBase.setDataConstraint(Constraint.DC_NONE); + else if ("INTEGRAL".equals(guarantee)) + scBase.setDataConstraint(Constraint.DC_INTEGRAL); + else if ("CONFIDENTIAL".equals(guarantee)) + scBase.setDataConstraint(Constraint.DC_CONFIDENTIAL); + else + { + Log.warn("Unknown user-data-constraint:" + guarantee); + scBase.setDataConstraint(Constraint.DC_CONFIDENTIAL); + } + } + Iterator iter = node.iterator("web-resource-collection"); + while (iter.hasNext()) + { + XmlParser.Node collection = (XmlParser.Node) iter.next(); + String name = collection.getString("web-resource-name", false, true); + Constraint sc = (Constraint) scBase.clone(); + sc.setName(name); + + Iterator iter2 = collection.iterator("url-pattern"); + while (iter2.hasNext()) + { + String url = ((XmlParser.Node) iter2.next()).toString(false, true); + url = normalizePattern(url); + + Iterator iter3 = collection.iterator("http-method"); + if (iter3.hasNext()) + { + while (iter3.hasNext()) + { + String method = ((XmlParser.Node) iter3.next()).toString(false, true); + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setMethod(method); + mapping.setPathSpec(url); + mapping.setConstraint(sc); + _constraintMappings.add(mapping); + } + } + else + { + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setPathSpec(url); + mapping.setConstraint(sc); + _constraintMappings.add(mapping); + } + } + } + } + catch (CloneNotSupportedException e) + { + Log.warn(e); + } + } + + protected void visitLoginConfig(Descriptor descriptor, XmlParser.Node node) throws Exception + { + //ServletSpec 3.0 p74 says elements present 0/1 time if specified in web.xml take + //precendece over any web-fragment. If not specified in web.xml, then if specified + //in a web-fragment must be the same across all web-fragments. + XmlParser.Node method = node.get("auth-method"); + if (method != null) + { + //handle auth-method merge + Origin o = _metaData.getOrigin("auth-method"); + switch (o) + { + case NotSet: + { + //not already set, so set it now + _securityHandler.setAuthMethod(method.toString(false, true)); + _metaData.setOrigin("auth-method", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //if it was already set by a web xml descriptor and we're parsing another web xml descriptor, then override it + if (!(descriptor instanceof FragmentDescriptor)) + { + _securityHandler.setAuthMethod(method.toString(false, true)); + _metaData.setOrigin("auth-method", descriptor); + } + break; + } + case WebFragment: + { + //it was already set by another fragment, if we're parsing a fragment, the values must match + if (!_securityHandler.getAuthMethod().equals(method.toString(false, true))) + throw new IllegalStateException("Conflicting auth-method value in "+descriptor.getResource()); + break; + } + } + + //handle realm-name merge + XmlParser.Node name = node.get("realm-name"); + String nameStr = (name == null ? "default" : name.toString(false, true)); + o = _metaData.getOrigin("realm-name"); + switch (o) + { + case NotSet: + { + //no descriptor has set the realm-name yet, so set it + _securityHandler.setRealmName(nameStr); + _metaData.setOrigin("realm-name", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //set by a web xml file (web.xml/web-default.xm/web-override.xml), only allow it to be changed by another web xml file + if (!(descriptor instanceof FragmentDescriptor)) + { + _securityHandler.setRealmName(nameStr); + _metaData.setOrigin("realm-name", descriptor); + } + break; + } + case WebFragment: + { + //a fragment set it, and we must be parsing another fragment, so the values must match + if (!_securityHandler.getRealmName().equals(nameStr)) + throw new IllegalStateException("Conflicting realm-name value in "+descriptor.getResource()); + break; + } + } + + if (Constraint.__FORM_AUTH.equals(_securityHandler.getAuthMethod())) + { + XmlParser.Node formConfig = node.get("form-login-config"); + if (formConfig != null) + { + String loginPageName = null; + XmlParser.Node loginPage = formConfig.get("form-login-page"); + if (loginPage != null) + loginPageName = loginPage.toString(false, true); + String errorPageName = null; + XmlParser.Node errorPage = formConfig.get("form-error-page"); + if (errorPage != null) + errorPageName = errorPage.toString(false, true); + + //handle form-login-page + o = _metaData.getOrigin("form-login-page"); + switch (o) + { + case NotSet: + { + //Never been set before, so accept it + _securityHandler.setInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE,loginPageName); + _metaData.setOrigin("form-login-page",descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //a web xml descriptor previously set it, only allow another one to change it (web.xml/web-default.xml/web-override.xml) + if (!(descriptor instanceof FragmentDescriptor)) + { + _securityHandler.setInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE,loginPageName); + _metaData.setOrigin("form-login-page",descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment previously set it. We must be parsing yet another web-fragment, so the values must agree + if (!_securityHandler.getInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE).equals(loginPageName)) + throw new IllegalStateException("Conflicting form-login-page value in "+descriptor.getResource()); + break; + } + } + + //handle form-error-page + o = _metaData.getOrigin("form-error-page"); + switch (o) + { + case NotSet: + { + //Never been set before, so accept it + _securityHandler.setInitParameter(FormAuthenticator.__FORM_ERROR_PAGE,errorPageName); + _metaData.setOrigin("form-error-page",descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //a web xml descriptor previously set it, only allow another one to change it (web.xml/web-default.xml/web-override.xml) + if (!(descriptor instanceof FragmentDescriptor)) + { + _securityHandler.setInitParameter(FormAuthenticator.__FORM_ERROR_PAGE,errorPageName); + _metaData.setOrigin("form-error-page",descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment previously set it. We must be parsing yet another web-fragment, so the values must agree + if (!_securityHandler.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE).equals(errorPageName)) + throw new IllegalStateException("Conflicting form-error-page value in "+descriptor.getResource()); + break; + } + } + } + else + { + throw new IllegalStateException("!form-login-config"); + } + } + } + } + + protected void visitSecurityRole(Descriptor descriptor, XmlParser.Node node) + { + //ServletSpec 3.0, p74 elements with multiplicity >1 are additive when merged + XmlParser.Node roleNode = node.get("role-name"); + String role = roleNode.toString(false, true); + _roles.add(role); + } + + + protected void visitFilter(Descriptor descriptor, XmlParser.Node node) + { + String name = node.getString("filter-name", false, true); + FilterHolder holder = _servletHandler.getFilter(name); + if (holder == null) + { + holder = _servletHandler.newFilterHolder(); + holder.setName(name); + _filters = LazyList.add(_filters, holder); + } + + String filter_class = node.getString("filter-class", false, true); + if (filter_class != null) + { + descriptor.addClassName(filter_class); + + Origin o = _metaData.getOrigin(name+".filter.filter-class"); + switch (o) + { + case NotSet: + { + //no class set yet + holder.setClassName(filter_class); + _metaData.setOrigin(name+".filter.filter-class", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //filter class was set in web.xml, only allow other web xml descriptors (override/default) to change it + if (!(descriptor instanceof FragmentDescriptor)) + { + holder.setClassName(filter_class); + _metaData.setOrigin(name+".filter.filter-class", descriptor); + } + break; + } + case WebFragment: + { + //the filter class was set up by a web fragment, all fragments must be the same + if (!holder.getClassName().equals(filter_class)) + throw new IllegalStateException("Conflicting filter-class for filter "+name+" in "+descriptor.getResource()); + break; + } + } + + } + + Iterator iter = node.iterator("init-param"); + while (iter.hasNext()) + { + XmlParser.Node paramNode = (XmlParser.Node) iter.next(); + String pname = paramNode.getString("param-name", false, true); + String pvalue = paramNode.getString("param-value", false, true); + + Origin origin = _metaData.getOrigin(name+".filter.init-param."+pname); + switch (origin) + { + case NotSet: + { + //init-param not already set, so set it + holder.setInitParameter(pname, pvalue); + _metaData.setOrigin(name+".filter.init-param."+pname, descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //previously set by a web xml descriptor, if we're parsing another web xml descriptor allow override + //otherwise just ignore it + if (!(descriptor instanceof FragmentDescriptor)) + { + holder.setInitParameter(pname, pvalue); + _metaData.setOrigin(name+".filter.init-param."+pname, descriptor); + } + break; + } + case WebFragment: + { + //previously set by a web-fragment, make sure that the value matches, otherwise its an error + if (!holder.getInitParameter(pname).equals(pvalue)) + throw new IllegalStateException("Mismatching init-param "+pname+"="+pvalue+" in "+descriptor.getResource()); + break; + } + } + } + + String async=node.getString("async-supported",false,true); + if (async!=null) + holder.setAsyncSupported(async.length()==0||Boolean.valueOf(async)); + if (async!=null) + { + boolean val = async.length()==0||Boolean.valueOf(async); + Origin o = _metaData.getOrigin(name+".filter.async-supported"); + switch (o) + { + case NotSet: + { + //set it + holder.setAsyncSupported(val); + _metaData.setOrigin(name+".filter.async-supported", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //async-supported set by previous web xml descriptor, only allow override if we're parsing another web descriptor(web.xml/web-override.xml/web-default.xml) + if (!(descriptor instanceof FragmentDescriptor)) + { + holder.setAsyncSupported(val); + _metaData.setOrigin(name+".filter.async-supported", descriptor); + } + break; + } + case WebFragment: + { + //async-supported set by another fragment, this fragment's value must match + if (holder.isAsyncSupported() != val) + throw new IllegalStateException("Conflicting async-supported="+async+" for filter "+name+" in "+descriptor.getResource()); + break; + } + } + } + + } + + protected void visitFilterMapping(Descriptor descriptor, XmlParser.Node node) + { + //Servlet Spec 3.0, p74 + //filter-mappings are always additive, whether from web xml descriptors (web.xml/web-default.xml/web-override.xml) or web-fragments. + + String filter_name = node.getString("filter-name", false, true); + + FilterMapping mapping = new FilterMapping(); + + mapping.setFilterName(filter_name); + + ArrayList paths = new ArrayList(); + Iterator iter = node.iterator("url-pattern"); + while (iter.hasNext()) + { + String p = ((XmlParser.Node) iter.next()).toString(false, true); + p = normalizePattern(p); + paths.add(p); + } + mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()])); + + ArrayList names = new ArrayList(); + iter = node.iterator("servlet-name"); + while (iter.hasNext()) + { + String n = ((XmlParser.Node) iter.next()).toString(false, true); + names.add(n); + } + mapping.setServletNames((String[]) names.toArray(new String[names.size()])); + + + List<DispatcherType> dispatches = new ArrayList<DispatcherType>(); + iter=node.iterator("dispatcher"); + while(iter.hasNext()) + { + String d=((XmlParser.Node)iter.next()).toString(false,true); + dispatches.add(FilterMapping.dispatch(d)); + } + + if (dispatches.size()>0) + mapping.setDispatcherTypes(EnumSet.copyOf(dispatches)); + + _filterMappings = LazyList.add(_filterMappings, mapping); + } + + + protected void visitListener(Descriptor descriptor, XmlParser.Node node) + { + String className = node.getString("listener-class", false, true); + Object listener = null; + try + { + if (className != null && className.length()> 0) + { + descriptor.addClassName(className); + + //Servlet Spec 3.0 p 74 + //Duplicate listener declarations don't result in duplicate listener instances + if (!LazyList.contains(_listenerClassNames, className)) + { + LazyList.add(_listenerClassNames, className); + Class listenerClass = _context.loadClass(className); + listener = newListenerInstance(listenerClass); + if (!(listener instanceof EventListener)) + { + Log.warn("Not an EventListener: " + listener); + return; + } + _metaData.setOrigin(className+".listener", descriptor); + _listeners = LazyList.add(_listeners, listener); + } + } + } + catch (Exception e) + { + Log.warn("Could not instantiate listener " + className, e); + return; + } + } + + protected void visitDistributable(Descriptor descriptor, XmlParser.Node node) + { + // the element has no content, so its simple presence + // indicates that the webapp is distributable... + //Servlet Spec 3.0 p.74 distributable only if all fragments are distributable + descriptor.setDistributable(true); + } + + protected Object newListenerInstance(Class<?extends EventListener> clazz) throws ServletException, InstantiationException, IllegalAccessException + { + try + { + return ((ServletContextHandler.Context)_context.getServletContext()).createListener(clazz); + } + catch (ServletException se) + { + Throwable cause = se.getRootCause(); + if (cause instanceof InstantiationException) + throw (InstantiationException)cause; + if (cause instanceof IllegalAccessException) + throw (IllegalAccessException)cause; + throw se; + } + } + + protected String getJSPServletName() + { + if (_jspServletName == null) + { + Map.Entry entry = _context.getServletHandler().getHolderEntry("test.jsp"); + if (entry != null) + { + ServletHolder holder = (ServletHolder) entry.getValue(); + _jspServletName = holder.getName(); + } + } + return _jspServletName; + } + + protected String normalizePattern(String p) + { + if (p != null && p.length() > 0 && !p.startsWith("/") && !p.startsWith("*")) return "/" + p; + return p; + } + + /** + * Generate the classpath (as a string) of all classloaders + * above the webapp's classloader. + * + * This is primarily used for jasper. + * @return + */ + protected String getSystemClassPath () + { + ClassLoader loader = _context.getClassLoader(); + if (loader.getParent() != null) + loader = loader.getParent(); + + StringBuilder classpath=new StringBuilder(); + while (loader != null && (loader instanceof URLClassLoader)) + { + URL[] urls = ((URLClassLoader)loader).getURLs(); + if (urls != null) + { + for (int i=0;i<urls.length;i++) + { + try + { + Resource resource = _context.newResource(urls[i]); + File file=resource.getFile(); + if (file!=null && file.exists()) + { + if (classpath.length()>0) + classpath.append(File.pathSeparatorChar); + classpath.append(file.getAbsolutePath()); + } + } + catch (IOException e) + { + Log.debug(e); + } + } + } + loader = loader.getParent(); + } + return classpath.toString(); + } +} diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/TagLibConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/TagLibConfiguration.java index d5b349b35c..f5dd88f39e 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/TagLibConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/TagLibConfiguration.java @@ -45,7 +45,8 @@ import org.eclipse.jetty.xml.XmlParser; * </bile> * * - * + * TODO - this has been superceded by the new TldScanner in jasper which uses ServletContainerInitializer to + * find all the listeners in tag libs and register them. */ public class TagLibConfiguration implements Configuration { diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index cea44168f2..139d868129 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -371,11 +371,16 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL - // Prepare for configuration + // Prepare for configuration + //Make a new MetaData to hold descriptor and annotation metadata + MetaData metadata = new MetaData(this); + setAttribute(MetaData.METADATA, metadata); + for (int i=0;i<_configurations.length;i++) _configurations[i].preConfigure(this); super.doStart(); + // Clean up after configuration for (int i=0;i<_configurations.length;i++) @@ -986,12 +991,12 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL protected void startContext() throws Exception { - - // Configure webapp for (int i=0;i<_configurations.length;i++) _configurations[i].configure(this); - + + //resolve the metadata + ((MetaData)getAttribute(MetaData.METADATA)).resolve(); super.startContext(); } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index 922952ac15..a4fd810f3f 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -23,6 +23,7 @@ public class WebInfConfiguration implements Configuration public static final String TEMPDIR_CREATED = "org.eclipse.jetty.tmpdirCreated"; public static final String CONTAINER_JAR_RESOURCES = "org.eclipse.jetty.containerJars"; public static final String WEB_INF_JAR_RESOURCES = "org.eclipse.jetty.webInfJars"; + public static final String WEB_INF_ORDERED_JAR_RESOURCES = "org.eclipse.jetty.webInfOrderedJars"; public static final String CONTAINER_JAR_PATTERN = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern"; public static final String WEBINF_JAR_PATTERN = "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern"; @@ -96,6 +97,7 @@ public class WebInfConfiguration implements Configuration } }; List<Resource> jars = findJars(context); + //Convert to uris for matching URI[] uris = null; if (jars != null) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java index f392ab188e..abb952d479 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java @@ -1,5 +1,5 @@ // ======================================================================== -// Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 2003-2010 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -34,52 +34,50 @@ public class WebXmlConfiguration implements Configuration /* ------------------------------------------------------------------------------- */ /** - * Process webdefaults.xml + * * * */ public void preConfigure (WebAppContext context) throws Exception { - // cannot configure if the context is already started - if (context.isStarted()) - { - if (Log.isDebugEnabled()) - { - Log.debug("Cannot configure webapp after it is started"); - } - return; - } - - //Get or create a processor to handle webdefaults, web.xml and the fragments - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (processor == null) - { - processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); - } - - //handle webdefault.xml + + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException("No metadata"); + + + //parse webdefault.xml String defaultsDescriptor = context.getDefaultsDescriptor(); if (defaultsDescriptor != null && defaultsDescriptor.length() > 0) { Resource dftResource = Resource.newSystemResource(defaultsDescriptor); if (dftResource == null) dftResource = context.newResource(defaultsDescriptor); - processor.parseDefaults (dftResource); - processor.processDefaults(); + metaData.setDefaults (dftResource); + } //parse, but don't process web.xml Resource webxml = findWebXml(context); if (webxml != null) { - processor.parseWebXml(webxml); + metaData.setWebXml(webxml); + } + + //parse but don't process override-web.xml + String overrideDescriptor = context.getOverrideDescriptor(); + if (overrideDescriptor != null && overrideDescriptor.length() > 0) + { + Resource orideResource = Resource.newSystemResource(overrideDescriptor); + if (orideResource == null) + orideResource = context.newResource(overrideDescriptor); + metaData.setOverride(orideResource); } } /* ------------------------------------------------------------------------------- */ /** - * Process web.xml, web-fragment.xml(s), override-web.xml + * Process web-default.xml, web.xml, override-web.xml * */ public void configure (WebAppContext context) throws Exception @@ -90,35 +88,35 @@ public class WebXmlConfiguration implements Configuration if (Log.isDebugEnabled()) Log.debug("Cannot configure webapp after it is started"); return; } + + MetaData metaData = (MetaData)context.getAttribute(MetaData.METADATA); + if (metaData == null) + throw new IllegalStateException("No metadata"); + + metaData.addDescriptorProcessor(new StandardDescriptorProcessor()); - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); - if (processor == null) + /* + StandardDescriptorProcessor descriptorProcessor = (StandardDescriptorProcessor)context.getAttribute(StandardDescriptorProcessor.STANDARD_PROCESSOR); + if (descriptorProcessor == null) { - processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); + descriptorProcessor = new StandardDescriptorProcessor(metaData); + context.setAttribute(StandardDescriptorProcessor.STANDARD_PROCESSOR, descriptorProcessor); } + + //process web-default.xml + descriptorProcessor.process(metaData.getWebDefault()); - //process web.xml (the effective web.xml???) - processor.processWebXml(); + //process web.xml + descriptorProcessor.process(metaData.getWebXml()); - //process override-web.xml - String overrideDescriptor = context.getOverrideDescriptor(); - if (overrideDescriptor != null && overrideDescriptor.length() > 0) - { - Resource orideResource = Resource.newSystemResource(overrideDescriptor); - if (orideResource == null) - orideResource = context.newResource(overrideDescriptor); - processor.parseOverride(orideResource); - processor.processOverride(); - } + //process override-web.xml + descriptorProcessor.process(metaData.getOverrideWeb()); + */ } public void postConfigure(WebAppContext context) throws Exception { - context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, null); - context.setAttribute(WebXmlProcessor.METADATA_COMPLETE, null); - context.setAttribute(WebXmlProcessor.WEBXML_VERSION, null); - context.setAttribute(WebXmlProcessor.WEBXML_CLASSNAMES, null); + context.setAttribute(MetaData.WEBXML_CLASSNAMES, null); } /* ------------------------------------------------------------------------------- */ diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlProcessor.java deleted file mode 100644 index 44bdb9f919..0000000000 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlProcessor.java +++ /dev/null @@ -1,1060 +0,0 @@ -// ======================================================================== -// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== - -package org.eclipse.jetty.webapp; - -import java.io.File; -import java.lang.reflect.Method; -import java.net.URL; -import java.util.ArrayList; -import java.util.EventListener; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.servlet.Servlet; -import javax.servlet.UnavailableException; - -import org.eclipse.jetty.http.security.Constraint; -import org.eclipse.jetty.security.ConstraintAware; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.SecurityHandler; -import org.eclipse.jetty.security.authentication.FormAuthenticator; -import org.eclipse.jetty.servlet.ErrorPageErrorHandler; -import org.eclipse.jetty.servlet.FilterHolder; -import org.eclipse.jetty.servlet.FilterMapping; -import org.eclipse.jetty.servlet.ServletHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.servlet.ServletMapping; -import org.eclipse.jetty.util.LazyList; -import org.eclipse.jetty.util.Loader; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.resource.Resource; -import org.eclipse.jetty.xml.XmlParser; - - - -/** - * WebXmlProcessor - * - */ -public class WebXmlProcessor -{ - public static final String WEB_PROCESSOR = "org.eclipse.jetty.webProcessor"; - public static final String METADATA_COMPLETE = "org.eclipse.jetty.metadataComplete"; - public static final String WEBXML_VERSION = "org.eclipse.jetty.webXmlVersion"; - public static final String WEBXML_CLASSNAMES = "org.eclipse.jetty.webXmlClassNames"; - - protected WebAppContext _context; - protected XmlParser _xmlParser; - protected Descriptor _webDefaultsRoot; - protected Descriptor _webXmlRoot; - protected List<Descriptor> _webFragmentRoots = new ArrayList<Descriptor>(); - protected Descriptor _webOverrideRoot; - - protected ServletHandler _servletHandler; - protected SecurityHandler _securityHandler; - protected Object _filters; - protected Object _filterMappings; - protected Object _servlets; - protected Object _servletMappings; - protected Object _listeners; - protected Object _welcomeFiles; - protected Set<String> _newRoles = new HashSet<String>(); - protected List<ConstraintMapping> _newConstraintMappings; - protected Map _errorPages; - protected boolean _hasJSP; - protected String _jspServletName; - protected String _jspServletClass; - protected boolean _defaultWelcomeFileList; - - - public class Descriptor - { - protected Resource _xml; - protected XmlParser.Node _root; - protected boolean _metadataComplete; - protected boolean _hasOrdering; - protected int _version; - protected ArrayList<String> _classNames; - - public Descriptor (Resource xml) - { - _xml = xml; - } - - public void parse () - throws Exception - { - if (_root == null) - { - _root = _xmlParser.parse(_xml.getURL().toString()); - processVersion(); - processOrdering(); - } - } - - public boolean isMetaDataComplete() - { - return _metadataComplete; - } - - - public XmlParser.Node getRoot () - { - return _root; - } - - public int getVersion () - { - return _version; - } - - public Resource getResource () - { - return _xml; - } - - public void process() - throws Exception - { - WebXmlProcessor.this.process(_root); - } - - private void processVersion () - { - String version = _root.getAttribute("version", "DTD"); - if ("2.5".equals(version)) - _version = 25; - else if ("2.4".equals(version)) - _version = 24; - else if ("3.0".equals(version)) - _version = 30; - else if ("DTD".equals(version)) - { - _version = 23; - String dtd = _xmlParser.getDTD(); - if (dtd != null && dtd.indexOf("web-app_2_2") >= 0) _version = 22; - } - - if (_version < 25) - _metadataComplete = true; // does not apply before 2.5 - else - _metadataComplete = Boolean.valueOf((String)_root.getAttribute("metadata-complete", "false")).booleanValue(); - - Log.debug(_xml.toString()+": Calculated metadatacomplete = " + _metadataComplete + " with version=" + version); - } - - private void processOrdering () - { - //TODO - } - - private void processClassNames () - { - _classNames = new ArrayList<String>(); - Iterator iter = _root.iterator(); - - while (iter.hasNext()) - { - Object o = iter.next(); - if (!(o instanceof XmlParser.Node)) continue; - XmlParser.Node node = (XmlParser.Node) o; - String name = node.getTag(); - if ("servlet".equals(name)) - { - String className = node.getString("servlet-class", false, true); - if (className != null) - _classNames.add(className); - } - else if ("filter".equals(name)) - { - String className = node.getString("filter-class", false, true); - if (className != null) - _classNames.add(className); - } - else if ("listener".equals(name)) - { - String className = node.getString("listener-class", false, true); - if (className != null) - _classNames.add(className); - } - } - } - - public ArrayList<String> getClassNames () - { - return _classNames; - } - } - - - - - public static XmlParser webXmlParser() throws ClassNotFoundException - { - XmlParser xmlParser=new XmlParser(); - //set up cache of DTDs and schemas locally - URL dtd22=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_2.dtd",true); - URL dtd23=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_3.dtd",true); - URL j2ee14xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_1_4.xsd",true); - URL webapp24xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_4.xsd",true); - URL webapp25xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_5.xsd",true); - URL webapp30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_3_0.xsd",true); - URL webcommon30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-common_3_0.xsd",true); - URL webfragment30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-fragment_3_0.xsd",true); - URL schemadtd=Loader.getResource(Servlet.class,"javax/servlet/resources/XMLSchema.dtd",true); - URL xmlxsd=Loader.getResource(Servlet.class,"javax/servlet/resources/xml.xsd",true); - URL webservice11xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_web_services_client_1_1.xsd",true); - URL webservice12xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/javaee_web_services_client_1_2.xsd",true); - URL datatypesdtd=Loader.getResource(Servlet.class,"javax/servlet/resources/datatypes.dtd",true); - - URL jsp20xsd = null; - URL jsp21xsd = null; - - try - { - Class jsp_page = Loader.loadClass(WebXmlConfiguration.class, "javax.servlet.jsp.JspPage"); - jsp20xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_0.xsd"); - jsp21xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_1.xsd"); - } - catch (Exception e) - { - Log.ignore(e); - } - finally - { - if (jsp20xsd == null) jsp20xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_0.xsd", true); - if (jsp21xsd == null) jsp21xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_1.xsd", true); - } - - redirect(xmlParser,"web-app_2_2.dtd",dtd22); - redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22); - redirect(xmlParser,"web.dtd",dtd23); - redirect(xmlParser,"web-app_2_3.dtd",dtd23); - redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23); - redirect(xmlParser,"XMLSchema.dtd",schemadtd); - redirect(xmlParser,"http://www.w3.org/2001/XMLSchema.dtd",schemadtd); - redirect(xmlParser,"-//W3C//DTD XMLSCHEMA 200102//EN",schemadtd); - redirect(xmlParser,"jsp_2_0.xsd",jsp20xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd",jsp20xsd); - redirect(xmlParser,"jsp_2_1.xsd",jsp21xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/jsp_2_1.xsd",jsp21xsd); - redirect(xmlParser,"j2ee_1_4.xsd",j2ee14xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd",j2ee14xsd); - redirect(xmlParser,"web-app_2_4.xsd",webapp24xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd",webapp24xsd); - redirect(xmlParser,"web-app_2_5.xsd",webapp25xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd",webapp25xsd); - redirect(xmlParser,"web-app_3_0.xsd",webapp30xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd",webapp30xsd); - redirect(xmlParser,"web-common_3_0.xsd",webcommon30xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-common_3_0.xsd",webcommon30xsd); - redirect(xmlParser,"web-fragment_3_0.xsd",webfragment30xsd); - redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd",webfragment30xsd); - redirect(xmlParser,"xml.xsd",xmlxsd); - redirect(xmlParser,"http://www.w3.org/2001/xml.xsd",xmlxsd); - redirect(xmlParser,"datatypes.dtd",datatypesdtd); - redirect(xmlParser,"http://www.w3.org/2001/datatypes.dtd",datatypesdtd); - redirect(xmlParser,"j2ee_web_services_client_1_1.xsd",webservice11xsd); - redirect(xmlParser,"http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd",webservice11xsd); - redirect(xmlParser,"javaee_web_services_client_1_2.xsd",webservice12xsd); - redirect(xmlParser,"http://www.ibm.com/webservices/xsd/javaee_web_services_client_1_2.xsd",webservice12xsd); - - return xmlParser; - } - - /* ------------------------------------------------------------------------------- */ - protected static void redirect(XmlParser parser, String resource, URL source) - { - if (source != null) parser.redirectEntity(resource, source); - } - - - public WebXmlProcessor (WebAppContext context) throws ClassNotFoundException - { - _context = context; - _xmlParser = webXmlParser(); - } - - public void parseDefaults (Resource webDefaults) - throws Exception - { - _webDefaultsRoot = new Descriptor(webDefaults); - _webDefaultsRoot.parse(); - } - - public void parseWebXml (Resource webXml) - throws Exception - { - _webXmlRoot = new Descriptor(webXml); - _webXmlRoot.parse(); - _webXmlRoot.processClassNames(); - _context.setAttribute(METADATA_COMPLETE, Boolean.valueOf(_webXmlRoot.isMetaDataComplete())); - _context.setAttribute(WEBXML_VERSION, Integer.valueOf(_webXmlRoot.getVersion())); - _context.setAttribute(WEBXML_CLASSNAMES, _webXmlRoot.getClassNames()); - } - - public void parseFragment (Resource fragment) - throws Exception - { - if (_webXmlRoot.isMetaDataComplete()) - return; //do not process anything else if main web.xml file is complete - - //Metadata-complete is not set, or there is no web.xml - Descriptor frag = new Descriptor(fragment); - frag.parse(); - _webFragmentRoots.add(frag); - } - - public void parseOverride (Resource override) - throws Exception - { - _xmlParser.setValidating(false); - _webOverrideRoot = new Descriptor(override); - _webOverrideRoot.parse(); - } - - - public void processDefaults () - throws Exception - { - _webDefaultsRoot.process(); - _defaultWelcomeFileList = _context.getWelcomeFiles() != null; - } - - public void processWebXml () - throws Exception - { - if (_webXmlRoot!=null) - _webXmlRoot.process(); - } - - public void processFragments () - throws Exception - { - for (Descriptor frag : _webFragmentRoots) - { - frag.process(); - } - } - - public void processOverride () - throws Exception - { - _webOverrideRoot.process(); - } - - public Descriptor getWebXml () - { - return _webXmlRoot; - } - - public Descriptor getOverrideWeb () - { - return _webOverrideRoot; - } - - public Descriptor getWebDefault () - { - return _webDefaultsRoot; - } - - public List<Descriptor> getFragments () - { - return _webFragmentRoots; - } - - - public void process (XmlParser.Node config) - throws Exception - { - - //Get the current objects from the context - _servletHandler = _context.getServletHandler(); - _securityHandler = (SecurityHandler)_context.getSecurityHandler(); - _filters = LazyList.array2List(_servletHandler.getFilters()); - _filterMappings = LazyList.array2List(_servletHandler.getFilterMappings()); - _servlets = LazyList.array2List(_servletHandler.getServlets()); - _servletMappings = LazyList.array2List(_servletHandler.getServletMappings()); - _listeners = LazyList.array2List(_context.getEventListeners()); - _welcomeFiles = LazyList.array2List(_context.getWelcomeFiles()); - - _newConstraintMappings=new ArrayList<ConstraintMapping>(); - _newRoles=new HashSet<String>(); - - _errorPages = _context.getErrorHandler() instanceof ErrorPageErrorHandler ? ((ErrorPageErrorHandler)_context.getErrorHandler()).getErrorPages() : null; - - Iterator iter = config.iterator(); - XmlParser.Node node = null; - while (iter.hasNext()) - { - try - { - Object o = iter.next(); - if (!(o instanceof XmlParser.Node)) continue; - node = (XmlParser.Node) o; - String name = node.getTag(); - initWebXmlElement(name, node); - } - catch (ClassNotFoundException e) - { - throw e; - } - catch (Exception e) - { - Log.warn("Configuration problem at " + node, e); - throw new UnavailableException("Configuration problem"); - } - } - - //Set the context with the results of the processing - _servletHandler.setFilters((FilterHolder[]) LazyList.toArray(_filters, FilterHolder.class)); - _servletHandler.setFilterMappings((FilterMapping[]) LazyList.toArray(_filterMappings, FilterMapping.class)); - _servletHandler.setServlets((ServletHolder[]) LazyList.toArray(_servlets, ServletHolder.class)); - _servletHandler.setServletMappings((ServletMapping[]) LazyList.toArray(_servletMappings, ServletMapping.class)); - _context.setEventListeners((EventListener[]) LazyList.toArray(_listeners, EventListener.class)); - _context.setWelcomeFiles((String[]) LazyList.toArray(_welcomeFiles, String.class)); - // TODO jaspi check this - if (_securityHandler instanceof ConstraintAware) - { - for (String role : _newRoles) - ((ConstraintAware)_securityHandler).addRole(role); - for (ConstraintMapping mapping : _newConstraintMappings) - ((ConstraintAware)_securityHandler).addConstraintMapping(mapping); - } - - if (_errorPages != null && _context.getErrorHandler() instanceof ErrorPageErrorHandler) - ((ErrorPageErrorHandler)_context.getErrorHandler()).setErrorPages(_errorPages); - } - - - - - /* ------------------------------------------------------------ */ - /** - * Handle web.xml element. This method is called for each top level element - * within the web.xml file. It may be specialized by derived WebAppHandlers - * to provide additional configuration and handling. - * - * @param element The element name - * @param node The node containing the element. - */ - protected void initWebXmlElement(String element, XmlParser.Node node) throws Exception - { - if ("display-name".equals(element)) - initDisplayName(node); - else if ("description".equals(element)) - { - } - else if ("context-param".equals(element)) - initContextParam(node); - else if ("servlet".equals(element)) - initServlet(node); - else if ("servlet-mapping".equals(element)) - initServletMapping(node); - else if ("session-config".equals(element)) - initSessionConfig(node); - else if ("mime-mapping".equals(element)) - initMimeConfig(node); - else if ("welcome-file-list".equals(element)) - initWelcomeFileList(node); - else if ("locale-encoding-mapping-list".equals(element)) - initLocaleEncodingList(node); - else if ("error-page".equals(element)) - initErrorPage(node); - else if ("taglib".equals(element)) - initTagLib(node); - else if ("jsp-config".equals(element)) - initJspConfig(node); - else if ("resource-ref".equals(element)) - { - if (Log.isDebugEnabled()) Log.debug("No implementation: " + node); - } - else if ("security-constraint".equals(element)) - initSecurityConstraint(node); - else if ("login-config".equals(element)) - initLoginConfig(node); - else if ("security-role".equals(element)) - initSecurityRole(node); - else if ("filter".equals(element)) - initFilter(node); - else if ("filter-mapping".equals(element)) - initFilterMapping(node); - else if ("listener".equals(element)) - initListener(node); - else if ("distributable".equals(element)) - initDistributable(node); - else if ("web-fragment".equals(element)) - { - } - else - { - if (Log.isDebugEnabled()) - { - Log.debug("Element {} not handled in {}", element, this); - Log.debug(node.toString()); - } - } - } - - /* ------------------------------------------------------------ */ - protected void initDisplayName(XmlParser.Node node) - { - _context.setDisplayName(node.toString(false, true)); - } - - /* ------------------------------------------------------------ */ - protected void initContextParam(XmlParser.Node node) - { - String name = node.getString("param-name", false, true); - String value = node.getString("param-value", false, true); - if (Log.isDebugEnabled()) Log.debug("ContextParam: " + name + "=" + value); - _context.getInitParams().put(name, value); - } - - /* ------------------------------------------------------------ */ - protected void initFilter(XmlParser.Node node) - { - String name = node.getString("filter-name", false, true); - FilterHolder holder = _servletHandler.getFilter(name); - if (holder == null) - { - holder = _servletHandler.newFilterHolder(); - holder.setName(name); - _filters = LazyList.add(_filters, holder); - } - - String filter_class = node.getString("filter-class", false, true); - if (filter_class != null) holder.setClassName(filter_class); - - Iterator iter = node.iterator("init-param"); - while (iter.hasNext()) - { - XmlParser.Node paramNode = (XmlParser.Node) iter.next(); - String pname = paramNode.getString("param-name", false, true); - String pvalue = paramNode.getString("param-value", false, true); - holder.setInitParameter(pname, pvalue); - } - - String async=node.getString("async-supported",false,true); - if (async!=null) - holder.setAsyncSupported(async.length()==0||Boolean.valueOf(async)); - - String timeout=node.getString("async-timeout",false,true); - // TODO set it - } - - /* ------------------------------------------------------------ */ - protected void initFilterMapping(XmlParser.Node node) - { - String filter_name = node.getString("filter-name", false, true); - - FilterMapping mapping = new FilterMapping(); - - mapping.setFilterName(filter_name); - - ArrayList paths = new ArrayList(); - Iterator iter = node.iterator("url-pattern"); - while (iter.hasNext()) - { - String p = ((XmlParser.Node) iter.next()).toString(false, true); - p = normalizePattern(p); - paths.add(p); - } - mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()])); - - ArrayList names = new ArrayList(); - iter = node.iterator("servlet-name"); - while (iter.hasNext()) - { - String n = ((XmlParser.Node) iter.next()).toString(false, true); - names.add(n); - } - mapping.setServletNames((String[]) names.toArray(new String[names.size()])); - - int dispatcher=FilterMapping.DEFAULT; - iter=node.iterator("dispatcher"); - while(iter.hasNext()) - { - String d=((XmlParser.Node)iter.next()).toString(false,true); - dispatcher|=FilterMapping.dispatch(d); - } - mapping.setDispatches(dispatcher); - - _filterMappings = LazyList.add(_filterMappings, mapping); - } - - /* ------------------------------------------------------------ */ - protected String normalizePattern(String p) - { - if (p != null && p.length() > 0 && !p.startsWith("/") && !p.startsWith("*")) return "/" + p; - return p; - } - - /* ------------------------------------------------------------ */ - protected void initServlet(XmlParser.Node node) - { - String id = node.getAttribute("id"); - - // initialize holder - String servlet_name = node.getString("servlet-name", false, true); - ServletHolder holder = _servletHandler.getServlet(servlet_name); - if (holder == null) - { - holder = _servletHandler.newServletHolder(); - holder.setName(servlet_name); - _servlets = LazyList.add(_servlets, holder); - } - - // init params - Iterator iParamsIter = node.iterator("init-param"); - while (iParamsIter.hasNext()) - { - XmlParser.Node paramNode = (XmlParser.Node) iParamsIter.next(); - String pname = paramNode.getString("param-name", false, true); - String pvalue = paramNode.getString("param-value", false, true); - holder.setInitParameter(pname, pvalue); - } - - String servlet_class = node.getString("servlet-class", false, true); - - // Handle JSP - if (id != null && id.equals("jsp")) - { - _jspServletName = servlet_name; - _jspServletClass = servlet_class; - try - { - Loader.loadClass(this.getClass(), servlet_class); - _hasJSP = true; - } - catch (ClassNotFoundException e) - { - Log.info("NO JSP Support for {}, did not find {}", _context.getContextPath(), servlet_class); - _hasJSP = false; - _jspServletClass = servlet_class = "org.eclipse.jetty.servlet.NoJspServlet"; - } - - // set the JSP log - if (_hasJSP) - { - try - { - Class<?> logFactory = Loader.loadClass(this.getClass(),"org.eclipse.jetty.jsp.JettyLog"); - Method init = logFactory.getMethod("init"); - Log.debug("Init JSP loggging "+init); - init.invoke(null); - } - catch (Exception e) - { - Log.warn(e.toString()); - Log.ignore(e); - } - } - - if (holder.getInitParameter("scratchdir") == null) - { - File tmp = _context.getTempDirectory(); - File scratch = new File(tmp, "jsp"); - if (!scratch.exists()) scratch.mkdir(); - holder.setInitParameter("scratchdir", scratch.getAbsolutePath()); - - if ("?".equals(holder.getInitParameter("classpath"))) - { - String classpath = _context.getClassPath(); - Log.debug("classpath=" + classpath); - if (classpath != null) holder.setInitParameter("classpath", classpath); - } - } - } - if (servlet_class != null) holder.setClassName(servlet_class); - - // Handler JSP file - String jsp_file = node.getString("jsp-file", false, true); - if (jsp_file != null) - { - holder.setForcedPath(jsp_file); - holder.setClassName(_jspServletClass); - } - - // handle startup - XmlParser.Node startup = node.get("load-on-startup"); - if (startup != null) - { - String s = startup.toString(false, true).toLowerCase(); - if (s.startsWith("t")) - { - Log.warn("Deprecated boolean load-on-startup. Please use integer"); - holder.setInitOrder(1); - } - else - { - int order = 0; - try - { - if (s != null && s.trim().length() > 0) order = Integer.parseInt(s); - } - catch (Exception e) - { - Log.warn("Cannot parse load-on-startup " + s + ". Please use integer"); - Log.ignore(e); - } - holder.setInitOrder(order); - } - } - - Iterator sRefsIter = node.iterator("security-role-ref"); - while (sRefsIter.hasNext()) - { - XmlParser.Node securityRef = (XmlParser.Node) sRefsIter.next(); - String roleName = securityRef.getString("role-name", false, true); - String roleLink = securityRef.getString("role-link", false, true); - if (roleName != null && roleName.length() > 0 && roleLink != null && roleLink.length() > 0) - { - if (Log.isDebugEnabled()) Log.debug("link role " + roleName + " to " + roleLink + " for " + this); - holder.setUserRoleLink(roleName, roleLink); - } - else - { - Log.warn("Ignored invalid security-role-ref element: " + "servlet-name=" + holder.getName() + ", " + securityRef); - } - } - - XmlParser.Node run_as = node.get("run-as"); - if (run_as != null) - { - String roleName = run_as.getString("role-name", false, true); - if (roleName != null) - holder.setRunAsRole(roleName); - } - - String async=node.getString("async-supported",false,true); - if (async!=null) - holder.setAsyncSupported(async.length()==0||Boolean.valueOf(async)); - - String timeout=node.getString("async-timeout",false,true); - // TODO set it - } - - /* ------------------------------------------------------------ */ - protected void initServletMapping(XmlParser.Node node) - { - String servlet_name = node.getString("servlet-name", false, true); - ServletMapping mapping = new ServletMapping(); - mapping.setServletName(servlet_name); - - ArrayList paths = new ArrayList(); - Iterator iter = node.iterator("url-pattern"); - while (iter.hasNext()) - { - String p = ((XmlParser.Node) iter.next()).toString(false, true); - p = normalizePattern(p); - paths.add(p); - } - mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()])); - - _servletMappings = LazyList.add(_servletMappings, mapping); - } - - /* ------------------------------------------------------------ */ - protected void initListener(XmlParser.Node node) - { - String className = node.getString("listener-class", false, true); - Object listener = null; - try - { - Class listenerClass = _context.loadClass(className); - listener = newListenerInstance(listenerClass); - if (!(listener instanceof EventListener)) - { - Log.warn("Not an EventListener: " + listener); - return; - } - _listeners = LazyList.add(_listeners, listener); - } - catch (Exception e) - { - Log.warn("Could not instantiate listener " + className, e); - return; - } - } - - /* ------------------------------------------------------------ */ - protected Object newListenerInstance(Class clazz) throws InstantiationException, IllegalAccessException - { - return clazz.newInstance(); - } - - /* ------------------------------------------------------------ */ - protected void initDistributable(XmlParser.Node node) - { - // the element has no content, so its simple presence - // indicates that the webapp is distributable... - if (!_context.isDistributable()) - _context.setDistributable(true); - } - - /* ------------------------------------------------------------ */ - protected void initSessionConfig(XmlParser.Node node) - { - XmlParser.Node tNode = node.get("session-timeout"); - if (tNode != null) - { - int timeout = Integer.parseInt(tNode.toString(false, true)); - _context.getSessionHandler().getSessionManager().setMaxInactiveInterval(timeout * 60); - } - } - - /* ------------------------------------------------------------ */ - protected void initMimeConfig(XmlParser.Node node) - { - String extension = node.getString("extension", false, true); - if (extension != null && extension.startsWith(".")) extension = extension.substring(1); - String mimeType = node.getString("mime-type", false, true); - _context.getMimeTypes().addMimeMapping(extension, mimeType); - } - - /* ------------------------------------------------------------ */ - protected void initWelcomeFileList(XmlParser.Node node) - { - if (_defaultWelcomeFileList) - _welcomeFiles = null; // erase welcome files from default web.xml - - _defaultWelcomeFileList = false; - Iterator iter = node.iterator("welcome-file"); - while (iter.hasNext()) - { - XmlParser.Node indexNode = (XmlParser.Node) iter.next(); - String welcome = indexNode.toString(false, true); - _welcomeFiles = LazyList.add(_welcomeFiles, welcome); - } - } - - /* ------------------------------------------------------------ */ - protected void initLocaleEncodingList(XmlParser.Node node) - { - Iterator iter = node.iterator("locale-encoding-mapping"); - while (iter.hasNext()) - { - XmlParser.Node mapping = (XmlParser.Node) iter.next(); - String locale = mapping.getString("locale", false, true); - String encoding = mapping.getString("encoding", false, true); - _context.addLocaleEncoding(locale, encoding); - } - } - - /* ------------------------------------------------------------ */ - protected void initErrorPage(XmlParser.Node node) - { - String error = node.getString("error-code", false, true); - if (error == null || error.length() == 0) error = node.getString("exception-type", false, true); - String location = node.getString("location", false, true); - - if (_errorPages == null) - _errorPages = new HashMap(); - _errorPages.put(error, location); - } - - /* ------------------------------------------------------------ */ - protected void initTagLib(XmlParser.Node node) - { - String uri = node.getString("taglib-uri", false, true); - String location = node.getString("taglib-location", false, true); - - _context.setResourceAlias(uri, location); - } - - /* ------------------------------------------------------------ */ - protected void initJspConfig(XmlParser.Node node) - { - for (int i = 0; i < node.size(); i++) - { - Object o = node.get(i); - if (o instanceof XmlParser.Node && "taglib".equals(((XmlParser.Node) o).getTag())) initTagLib((XmlParser.Node) o); - } - - // Map URLs from jsp property groups to JSP servlet. - // this is more JSP stupidness creaping into the servlet spec - Iterator iter = node.iterator("jsp-property-group"); - Object paths = null; - while (iter.hasNext()) - { - XmlParser.Node group = (XmlParser.Node) iter.next(); - Iterator iter2 = group.iterator("url-pattern"); - while (iter2.hasNext()) - { - String url = ((XmlParser.Node) iter2.next()).toString(false, true); - url = normalizePattern(url); - paths = LazyList.add(paths, url); - } - } - - if (LazyList.size(paths) > 0) - { - String jspName = getJSPServletName(); - if (jspName != null) - { - ServletMapping mapping = new ServletMapping(); - mapping.setServletName(jspName); - mapping.setPathSpecs(LazyList.toStringArray(paths)); - _servletMappings = LazyList.add(_servletMappings, mapping); - } - } - } - - /* ------------------------------------------------------------ */ - protected void initSecurityConstraint(XmlParser.Node node) - { - Constraint scBase = new Constraint(); - - try - { - XmlParser.Node auths = node.get("auth-constraint"); - - if (auths != null) - { - scBase.setAuthenticate(true); - // auth-constraint - Iterator iter = auths.iterator("role-name"); - Object roles = null; - while (iter.hasNext()) - { - String role = ((XmlParser.Node) iter.next()).toString(false, true); - roles = LazyList.add(roles, role); - } - scBase.setRoles(LazyList.toStringArray(roles)); - } - - XmlParser.Node data = node.get("user-data-constraint"); - if (data != null) - { - data = data.get("transport-guarantee"); - String guarantee = data.toString(false, true).toUpperCase(); - if (guarantee == null || guarantee.length() == 0 || "NONE".equals(guarantee)) - scBase.setDataConstraint(Constraint.DC_NONE); - else if ("INTEGRAL".equals(guarantee)) - scBase.setDataConstraint(Constraint.DC_INTEGRAL); - else if ("CONFIDENTIAL".equals(guarantee)) - scBase.setDataConstraint(Constraint.DC_CONFIDENTIAL); - else - { - Log.warn("Unknown user-data-constraint:" + guarantee); - scBase.setDataConstraint(Constraint.DC_CONFIDENTIAL); - } - } - Iterator iter = node.iterator("web-resource-collection"); - while (iter.hasNext()) - { - XmlParser.Node collection = (XmlParser.Node) iter.next(); - String name = collection.getString("web-resource-name", false, true); - Constraint sc = (Constraint) scBase.clone(); - sc.setName(name); - - Iterator iter2 = collection.iterator("url-pattern"); - while (iter2.hasNext()) - { - String url = ((XmlParser.Node) iter2.next()).toString(false, true); - url = normalizePattern(url); - - Iterator iter3 = collection.iterator("http-method"); - if (iter3.hasNext()) - { - while (iter3.hasNext()) - { - String method = ((XmlParser.Node) iter3.next()).toString(false, true); - ConstraintMapping mapping = new ConstraintMapping(); - mapping.setMethod(method); - mapping.setPathSpec(url); - mapping.setConstraint(sc); - _newConstraintMappings.add(mapping); - } - } - else - { - ConstraintMapping mapping = new ConstraintMapping(); - mapping.setPathSpec(url); - mapping.setConstraint(sc); - _newConstraintMappings.add(mapping); - } - } - } - } - catch (CloneNotSupportedException e) - { - Log.warn(e); - } - - } - - /* ------------------------------------------------------------ */ - protected void initLoginConfig(XmlParser.Node node) throws Exception - { - XmlParser.Node method = node.get("auth-method"); - if (method != null) - { - XmlParser.Node name = node.get("realm-name"); - _securityHandler.setRealmName(name == null ? "default" : name.toString(false, true)); - _securityHandler.setAuthMethod(method.toString(false, true)); - - - if (Constraint.__FORM_AUTH.equals(_securityHandler.getAuthMethod())) - { - XmlParser.Node formConfig = node.get("form-login-config"); - if (formConfig != null) - { - String loginPageName = null; - XmlParser.Node loginPage = formConfig.get("form-login-page"); - if (loginPage != null) - loginPageName = loginPage.toString(false, true); - String errorPageName = null; - XmlParser.Node errorPage = formConfig.get("form-error-page"); - if (errorPage != null) - errorPageName = errorPage.toString(false, true); - _securityHandler.setInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE,loginPageName); - _securityHandler.setInitParameter(FormAuthenticator.__FORM_ERROR_PAGE,errorPageName); - } - else - { - throw new IllegalArgumentException("!form-login-config"); - } - } - } - } - - /* ------------------------------------------------------------ */ - protected void initSecurityRole(XmlParser.Node node) - { - XmlParser.Node roleNode = node.get("role-name"); - String role = roleNode.toString(false, true); - _newRoles.add(role); - } - - /* ------------------------------------------------------------ */ - protected String getJSPServletName() - { - if (_jspServletName == null) - { - Map.Entry entry = _context.getServletHandler().getHolderEntry("test.jsp"); - if (entry != null) - { - ServletHolder holder = (ServletHolder) entry.getValue(); - _jspServletName = holder.getName(); - } - } - return _jspServletName; - } -} diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java new file mode 100644 index 0000000000..7e20c21da2 --- /dev/null +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java @@ -0,0 +1,939 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.webapp; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.MetaData.AbsoluteOrdering; +import org.eclipse.jetty.webapp.MetaData.RelativeOrdering; + +/** + * OrderingTest + * + * + */ +public class OrderingTest extends TestCase +{ + public class TestResource extends Resource + { + public String _name; + + public TestResource (String name) + { + _name =name; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#addPath(java.lang.String) + */ + public Resource addPath(String path) throws IOException, MalformedURLException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#delete() + */ + public boolean delete() throws SecurityException + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#exists() + */ + public boolean exists() + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getFile() + */ + public File getFile() throws IOException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getInputStream() + */ + public InputStream getInputStream() throws IOException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getName() + */ + public String getName() + { + return _name; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getOutputStream() + */ + public OutputStream getOutputStream() throws IOException, SecurityException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#getURL() + */ + public URL getURL() + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#isContainedIn(org.eclipse.jetty.util.resource.Resource) + */ + public boolean isContainedIn(Resource r) throws MalformedURLException + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#isDirectory() + */ + public boolean isDirectory() + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#lastModified() + */ + public long lastModified() + { + // TODO Auto-generated method stub + return 0; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#length() + */ + public long length() + { + // TODO Auto-generated method stub + return 0; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#list() + */ + public String[] list() + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#release() + */ + public void release() + { + // TODO Auto-generated method stub + + } + + /** + * @see org.eclipse.jetty.util.resource.Resource#renameTo(org.eclipse.jetty.util.resource.Resource) + */ + public boolean renameTo(Resource dest) throws SecurityException + { + // TODO Auto-generated method stub + return false; + } + + } + + + public void testRelativeOrdering0 () + throws Exception + { + //Example from ServletSpec p.70 + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + List<Resource> resources = new ArrayList<Resource>(); + metaData._ordering = metaData.new RelativeOrdering(); + + //A: after others, after C + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + f1._otherType = FragmentDescriptor.OtherType.After; + //((RelativeOrdering)metaData._ordering).addAfterOthers(r1); + f1._afters.add("C"); + + //B: before others + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); + f2._otherType = FragmentDescriptor.OtherType.Before; + //((RelativeOrdering)metaData._ordering).addBeforeOthers(r2); + + //C: after others + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3, f3); + f3._otherType = FragmentDescriptor.OtherType.After; + //((RelativeOrdering)metaData._ordering).addAfterOthers(r3); + + //D: no ordering + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData); + f4._name="D"; + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4, f4); + f4._otherType = FragmentDescriptor.OtherType.None; + //((RelativeOrdering)metaData._ordering).addNoOthers(r4); + + //E: no ordering + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor(r5, metaData); + f5._name="E"; + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5, f5); + f5._otherType = FragmentDescriptor.OtherType.None; + //((RelativeOrdering)metaData._ordering).addNoOthers(r5); + + //F: before others, before B + TestResource jar6 = new TestResource("F"); + resources.add(jar6); + TestResource r6 = new TestResource("F/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor(r6, metaData); + f6._name="F"; + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6,f6); + f6._otherType = FragmentDescriptor.OtherType.Before; + //((RelativeOrdering)metaData._ordering).addBeforeOthers(r6); + f6._befores.add("B"); + + // + // p.70 outcome: F, B, D, E, C, A + // + String[] outcomes = {"FBDECA"}; + List<Resource> orderedList = metaData._ordering.order(resources); + + String result = ""; + for (Resource r:orderedList) + result+=(((TestResource)r)._name); + + if (!checkResult(result, outcomes)) + fail("No outcome matched "+result); + } + + + + + public void testRelativeOrdering1 () + throws Exception + { + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); + + //Example from ServletSpec p.70-71 + //No name: after others, before C + TestResource jar1 = new TestResource("plain"); + resources.add(jar1); + TestResource r1 = new TestResource("plain/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = FragmentDescriptor.NAMELESS+"1"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); + f1._otherType = FragmentDescriptor.OtherType.After; + //((RelativeOrdering)metaData._ordering).addAfterOthers(f1); + f1._befores.add("C"); + + //B: before others + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); + f2._otherType = FragmentDescriptor.OtherType.Before; + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f2); + + //C: no ordering + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addNoOthers(f3); + f3._otherType = FragmentDescriptor.OtherType.None; + + //D: after others + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData); + f4._name="D"; + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4,f4); + //((RelativeOrdering)metaData._ordering).addAfterOthers(f4); + f4._otherType = FragmentDescriptor.OtherType.After; + + //E: before others + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor(r5, metaData); + f5._name="E"; + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5,f5); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f5); + f5._otherType = FragmentDescriptor.OtherType.Before; + + //F: no ordering + TestResource jar6 = new TestResource("F"); + resources.add(jar6); + TestResource r6 = new TestResource("F/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor(r6, metaData); + f6._name="F"; + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6,f6); + //((RelativeOrdering)metaData._ordering).addNoOthers(f6); + f6._otherType = FragmentDescriptor.OtherType.None; + + List<Resource> orderedList = metaData._ordering.order(resources); + + // p.70-71 Possible outcomes are: + // B, E, F, noname, C, D + // B, E, F, noname, D, C + // E, B, F, noname, C, D + // E, B, F, noname, D, C + // E, B, F, D, noname, C + // + String[] outcomes = {"BEFplainCD", + "BEFplainDC", + "EBFplainCD", + "EBFplainDC", + "EBFDplain"}; + + String orderedNames = ""; + for (Resource r:orderedList) + orderedNames+=(((TestResource)r)._name); + + if (!checkResult(orderedNames, outcomes)) + fail("No outcome matched "+orderedNames); + } + + + public void testRelativeOrdering2 () + throws Exception + { + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); + + //Example from Spec p. 71-72 + + //A: after B + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + //((RelativeOrdering)metaData._ordering).addNoOthers(f1); + f1._otherType = FragmentDescriptor.OtherType.None; + f1._afters.add("B"); + + //B: no order + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); + //((RelativeOrdering)metaData._ordering).addNoOthers(f2); + f2._otherType = FragmentDescriptor.OtherType.None; + + //C: before others + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f3); + f3._otherType = FragmentDescriptor.OtherType.Before; + + //D: no order + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData); + f4._name="D"; + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4, f4); + //((RelativeOrdering)metaData._ordering).addNoOthers(f4); + f4._otherType = FragmentDescriptor.OtherType.None; + // + // p.71-72 possible outcomes are: + // C,B,D,A + // C,D,B,A + // C,B,A,D + // + String[] outcomes = {"CBDA", + "CDBA", + "CBAD"}; + + + List<Resource> orderedList = metaData._ordering.order(resources); + String result = ""; + for (Resource r:orderedList) + result+=(((TestResource)r)._name); + + if (!checkResult(result, outcomes)) + fail ("No outcome matched "+result); + } + + + public void testRelativeOrdering3 () + throws Exception + { + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); + + //A: after others, before C + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + //((RelativeOrdering)metaData._ordering).addAfterOthers(f1); + f1._otherType = FragmentDescriptor.OtherType.After; + f1._befores.add("C"); + + //B: before others, before C + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f2); + f2._otherType = FragmentDescriptor.OtherType.Before; + f2._befores.add("C"); + + //C: no ordering + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addNoOthers(f3); + f3._otherType = FragmentDescriptor.OtherType.None; + + //result: BAC + String[] outcomes = {"BAC"}; + + List<Resource> orderedList = metaData._ordering.order(resources); + String result = ""; + for (Resource r:orderedList) + result+=(((TestResource)r)._name); + + if (!checkResult(result, outcomes)) + fail ("No outcome matched "+result); + } + + public void testCircular1 () + throws Exception + { + + //A: after B + //B: after A + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); + + //A: after B + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + //((RelativeOrdering)metaData._ordering).addNoOthers(f1); + f1._otherType = FragmentDescriptor.OtherType.None; + f1._afters.add("B"); + + //B: after A + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); + //((RelativeOrdering)metaData._ordering).addNoOthers(f2); + f2._otherType = FragmentDescriptor.OtherType.None; + f2._afters.add("A"); + + try + { + List<Resource> orderedList = metaData._ordering.order(resources); + fail("No circularity detected"); + } + catch (Exception e) + { + assertTrue (e instanceof IllegalStateException); + } + } + + + + + public void testInvalid1 () + throws Exception + { + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); + + //A: after others, before C + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); + //((RelativeOrdering)metaData._ordering).addAfterOthers(r1); + f1._otherType = FragmentDescriptor.OtherType.After; + f1._befores.add("C"); + + //B: before others, after C + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(r2); + f2._otherType = FragmentDescriptor.OtherType.Before; + f2._afters.add("C"); + + //C: no ordering + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addNoOthers(r3); + f3._otherType = FragmentDescriptor.OtherType.None; + + try + { + List<Resource> orderedList = metaData._ordering.order(resources); + String result = ""; + for (Resource r:orderedList) + result +=((TestResource)r)._name; + System.err.println("Invalid Result = "+result); + fail("A and B have an impossible relationship to C"); + } + catch (Exception e) + { + assertTrue (e instanceof IllegalStateException); + } + } + + + public void testAbsoluteOrdering1 () + throws Exception + { + // + // A,B,C,others + // + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new AbsoluteOrdering(); + ((AbsoluteOrdering)metaData._ordering).add("A"); + ((AbsoluteOrdering)metaData._ordering).add("B"); + ((AbsoluteOrdering)metaData._ordering).add("C"); + ((AbsoluteOrdering)metaData._ordering).addOthers(); + + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); + + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); + + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3, f3); + + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor((Resource)null, metaData); + f4._name="D"; + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4, f4); + + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor((Resource)null, metaData); + f5._name="E"; + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5, f5); + + TestResource jar6 = new TestResource("plain"); + resources.add(jar6); + TestResource r6 = new TestResource ("plain/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor((Resource)null, metaData); + f6._name=FragmentDescriptor.NAMELESS+"1"; + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6, f6); + + List<Resource> list = metaData._ordering.order(resources); + + String[] outcomes = {"ABCDEplain"}; + String result = ""; + for (Resource r:list) + result += ((TestResource)r)._name; + + if (!checkResult(result, outcomes)) + fail("No outcome matched "+result); + } + + + public void testAbsoluteOrdering2 () + throws Exception + { + // C,B,A + List<Resource> resources = new ArrayList<Resource>(); + + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new AbsoluteOrdering(); + ((AbsoluteOrdering)metaData._ordering).add("C"); + ((AbsoluteOrdering)metaData._ordering).add("B"); + ((AbsoluteOrdering)metaData._ordering).add("A"); + + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); + + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); + + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor(r4, metaData); + f4._name="D"; + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4,f4); + + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor(r5, metaData); + f5._name="E"; + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5,f5); + + TestResource jar6 = new TestResource("plain"); + resources.add(jar6); + TestResource r6 = new TestResource("plain/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor(r6, metaData); + f6._name=FragmentDescriptor.NAMELESS+"1"; + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6,f6); + + List<Resource> list = metaData._ordering.order(resources); + String[] outcomes = {"CBA"}; + String result = ""; + for (Resource r:list) + result += ((TestResource)r)._name; + + + if (!checkResult(result, outcomes)) + fail("No outcome matched "+result); + } + + public void testAbsoluteOrdering3 () + throws Exception + { + //empty <absolute-ordering> + + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new AbsoluteOrdering(); + List<Resource> resources = new ArrayList<Resource>(); + + resources.add(new TestResource("A")); + resources.add(new TestResource("B")); + + List<Resource> list = metaData._ordering.order(resources); + assertTrue(list.isEmpty()); + } + + + public void testRelativeOrderingWithPlainJars () + throws Exception + { + //B,A,C other jars with no fragments + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new RelativeOrdering(); + + //A: after others, before C + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1, f1); + //((RelativeOrdering)metaData._ordering).addAfterOthers(f1); + f1._otherType = FragmentDescriptor.OtherType.After; + f1._befores.add("C"); + + //B: before others, before C + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2,f2); + //((RelativeOrdering)metaData._ordering).addBeforeOthers(f2); + f2._otherType = FragmentDescriptor.OtherType.Before; + f2._befores.add("C"); + + //C: after A + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3,f3); + //((RelativeOrdering)metaData._ordering).addNoOthers(f3); + f3._otherType = FragmentDescriptor.OtherType.None; + f3._afters.add("A"); + + //No fragment jar 1 + TestResource r4 = new TestResource("plain1"); + resources.add(r4); + + //No fragment jar 2 + TestResource r5 = new TestResource("plain2"); + resources.add(r5); + + //result: BAC + String[] outcomes = {"Bplain1plain2AC"}; + + List<Resource> orderedList = metaData._ordering.order(resources); + String result = ""; + for (Resource r:orderedList) + result+=(((TestResource)r)._name); + + if (!checkResult(result, outcomes)) + fail ("No outcome matched "+result); + } + + public void testAbsoluteOrderingWithPlainJars() + throws Exception + { + // + // A,B,C,others + // + List<Resource> resources = new ArrayList<Resource>(); + WebAppContext wac = new WebAppContext(); + MetaData metaData = new MetaData(wac); + metaData._ordering = metaData.new AbsoluteOrdering(); + ((AbsoluteOrdering)metaData._ordering).add("A"); + ((AbsoluteOrdering)metaData._ordering).add("B"); + ((AbsoluteOrdering)metaData._ordering).add("C"); + ((AbsoluteOrdering)metaData._ordering).addOthers(); + + TestResource jar1 = new TestResource("A"); + resources.add(jar1); + TestResource r1 = new TestResource("A/web-fragment.xml"); + FragmentDescriptor f1 = new FragmentDescriptor(r1, metaData); + f1._name = "A"; + metaData._webFragmentNameMap.put(f1._name, f1); + metaData._webFragmentResourceMap.put(jar1,f1); + + TestResource jar2 = new TestResource("B"); + resources.add(jar2); + TestResource r2 = new TestResource("B/web-fragment.xml"); + FragmentDescriptor f2 = new FragmentDescriptor(r2, metaData); + f2._name="B"; + metaData._webFragmentNameMap.put(f2._name, f2); + metaData._webFragmentResourceMap.put(jar2, f2); + + TestResource jar3 = new TestResource("C"); + resources.add(jar3); + TestResource r3 = new TestResource("C/web-fragment.xml"); + FragmentDescriptor f3 = new FragmentDescriptor(r3, metaData); + f3._name="C"; + metaData._webFragmentNameMap.put(f3._name, f3); + metaData._webFragmentResourceMap.put(jar3, f3); + + TestResource jar4 = new TestResource("D"); + resources.add(jar4); + TestResource r4 = new TestResource("D/web-fragment.xml"); + FragmentDescriptor f4 = new FragmentDescriptor((Resource)null, metaData); + f4._name="D"; + metaData._webFragmentNameMap.put(f4._name, f4); + metaData._webFragmentResourceMap.put(jar4, f4); + + TestResource jar5 = new TestResource("E"); + resources.add(jar5); + TestResource r5 = new TestResource("E/web-fragment.xml"); + FragmentDescriptor f5 = new FragmentDescriptor((Resource)null, metaData); + f5._name="E"; + metaData._webFragmentNameMap.put(f5._name, f5); + metaData._webFragmentResourceMap.put(jar5, f5); + + TestResource jar6 = new TestResource("plain"); + resources.add(jar6); + TestResource r6 = new TestResource("plain/web-fragment.xml"); + FragmentDescriptor f6 = new FragmentDescriptor((Resource)null, metaData); + f6._name=FragmentDescriptor.NAMELESS+"1"; + metaData._webFragmentNameMap.put(f6._name, f6); + metaData._webFragmentResourceMap.put(jar6, f6); + + //plain jar + TestResource r7 = new TestResource("plain1"); + resources.add(r7); + + TestResource r8 = new TestResource("plain2"); + resources.add(r8); + + List<Resource> list = metaData._ordering.order(resources); + + String[] outcomes = {"ABCDEplainplain1plain2"}; + String result = ""; + for (Resource r:list) + result += ((TestResource)r)._name; + + if (!checkResult(result, outcomes)) + fail("No outcome matched "+result); + } + + + + public boolean checkResult (String result, String[] outcomes) + { + boolean matched = false; + for (String s:outcomes) + { + if (s.equals(result)) + matched = true; + } + return matched; + } +} |