-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements. See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-\r
-package org.apache.catalina.deploy;\r
-\r
-import java.net.URL;\r
-import java.util.ArrayList;\r
-import java.util.EnumSet;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.Iterator;\r
-import java.util.LinkedHashMap;\r
-import java.util.LinkedHashSet;\r
-import java.util.LinkedList;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Map.Entry;\r
-import java.util.Set;\r
-\r
-import javax.servlet.MultipartConfigElement;\r
-import javax.servlet.SessionCookieConfig;\r
-import javax.servlet.SessionTrackingMode;\r
-import javax.servlet.descriptor.JspPropertyGroupDescriptor;\r
-import javax.servlet.descriptor.TaglibDescriptor;\r
-\r
-import org.apache.catalina.Context;\r
-import org.apache.catalina.Wrapper;\r
-import org.apache.catalina.core.ApplicationJspPropertyGroupDescriptor;\r
-import org.apache.catalina.core.ApplicationTaglibDescriptor;\r
-import org.apache.tomcat.util.res.StringManager;\r
-\r
-/**\r
- * Representation of common elements of web.xml and web-fragment.xml. Provides\r
- * a repository for parsed data before the elements are merged.\r
- * Validation is spread between multiple classes:\r
- * The digester checks for structural correctness (eg single login-config)\r
- * This class checks for invalid duplicates (eg filter/servlet names)\r
- * StandardContext will check validity of values (eg URL formats etc)\r
- */\r
-public class WebXml {\r
- \r
- protected static final String ORDER_OTHERS =\r
- "org.apache.catalina.order.others";\r
- \r
- private static final StringManager sm =\r
- StringManager.getManager(Constants.Package);\r
-\r
- private static final org.apache.juli.logging.Log log=\r
- org.apache.juli.logging.LogFactory.getLog(WebXml.class);\r
-\r
- // Global defaults are overridable but Servlets and Servlet mappings need to\r
- // be unique. Duplicates normally trigger an error. This flag indicates if\r
- // newly added Servlet elements are marked as overridable.\r
- private boolean overridable = false;\r
- public boolean isOverridable() {\r
- return overridable;\r
- }\r
- public void setOverridable(boolean overridable) {\r
- this.overridable = overridable;\r
- }\r
-\r
- // web.xml only elements\r
- // Absolute Ordering\r
- private Set<String> absoluteOrdering = null;\r
- public void addAbsoluteOrdering(String fragmentName) {\r
- if (absoluteOrdering == null) {\r
- absoluteOrdering = new LinkedHashSet<String>();\r
- }\r
- absoluteOrdering.add(fragmentName);\r
- }\r
- public void addAbsoluteOrderingOthers() {\r
- if (absoluteOrdering == null) {\r
- absoluteOrdering = new LinkedHashSet<String>();\r
- }\r
- absoluteOrdering.add(ORDER_OTHERS);\r
- }\r
- public Set<String> getAbsoluteOrdering() {\r
- return absoluteOrdering;\r
- }\r
-\r
- // web-fragment.xml only elements\r
- // Relative ordering\r
- private Set<String> after = new LinkedHashSet<String>();\r
- public void addAfterOrdering(String fragmentName) {\r
- after.add(fragmentName);\r
- }\r
- public void addAfterOrderingOthers() {\r
- if (before.contains(ORDER_OTHERS)) {\r
- throw new IllegalArgumentException(sm.getString(\r
- "webXml.multipleOther"));\r
- }\r
- after.add(ORDER_OTHERS);\r
- }\r
- public Set<String> getAfterOrdering() { return after; }\r
- \r
- private Set<String> before = new LinkedHashSet<String>();\r
- public void addBeforeOrdering(String fragmentName) {\r
- before.add(fragmentName);\r
- }\r
- public void addBeforeOrderingOthers() {\r
- if (after.contains(ORDER_OTHERS)) {\r
- throw new IllegalArgumentException(sm.getString(\r
- "webXml.multipleOther"));\r
- }\r
- before.add(ORDER_OTHERS);\r
- }\r
- public Set<String> getBeforeOrdering() { return before; }\r
-\r
- // Common elements and attributes\r
- \r
- // Required attribute of web-app element\r
- public String getVersion() {\r
- StringBuilder sb = new StringBuilder(3);\r
- sb.append(majorVersion);\r
- sb.append('.');\r
- sb.append(minorVersion);\r
- return sb.toString();\r
- }\r
- /**\r
- * Set the version for this web.xml file\r
- * @param version Values of <code>null</code> will be ignored\r
- */\r
- public void setVersion(String version) {\r
- if (version == null) return;\r
- \r
- // Update major and minor version\r
- // Expected format is n.n - allow for any number of digits just in case\r
- String major = null;\r
- String minor = null;\r
- int split = version.indexOf('.');\r
- if (split < 0) {\r
- // Major only\r
- major = version;\r
- } else {\r
- major = version.substring(0, split);\r
- minor = version.substring(split + 1);\r
- }\r
- if (major == null || major.length() == 0) {\r
- majorVersion = 0;\r
- } else {\r
- try {\r
- majorVersion = Integer.parseInt(major);\r
- } catch (NumberFormatException nfe) {\r
- log.warn(sm.getString("webXml.version.nfe", major, version),\r
- nfe);\r
- majorVersion = 0;\r
- }\r
- }\r
- \r
- if (minor == null || minor.length() == 0) {\r
- minorVersion = 0;\r
- } else {\r
- try {\r
- minorVersion = Integer.parseInt(minor);\r
- } catch (NumberFormatException nfe) {\r
- log.warn(sm.getString("webXml.version.nfe", minor, version),\r
- nfe);\r
- minorVersion = 0;\r
- }\r
- }\r
- }\r
-\r
-\r
- // Optional publicId attribute\r
- private String publicId = null;\r
- public String getPublicId() { return publicId; }\r
- public void setPublicId(String publicId) {\r
- // Update major and minor version\r
- if (publicId == null) {\r
- // skip\r
- } else if (org.apache.catalina.startup.Constants.WebSchemaPublicId_30.\r
- equalsIgnoreCase(publicId) ||\r
- org.apache.catalina.startup.Constants.WebFragmentSchemaPublicId_30.\r
- equalsIgnoreCase(publicId)) {\r
- majorVersion = 3;\r
- minorVersion = 0;\r
- this.publicId = publicId;\r
- } else if (org.apache.catalina.startup.Constants.WebSchemaPublicId_25.\r
- equalsIgnoreCase(publicId)) {\r
- majorVersion = 2;\r
- minorVersion = 5;\r
- this.publicId = publicId;\r
- } else if (org.apache.catalina.startup.Constants.WebSchemaPublicId_24.\r
- equalsIgnoreCase(publicId)) {\r
- majorVersion = 2;\r
- minorVersion = 4;\r
- this.publicId = publicId;\r
- } else if (org.apache.catalina.startup.Constants.WebDtdPublicId_23.\r
- equalsIgnoreCase(publicId)) {\r
- majorVersion = 2;\r
- minorVersion = 3;\r
- this.publicId = publicId;\r
- } else if (org.apache.catalina.startup.Constants.WebDtdPublicId_22.\r
- equalsIgnoreCase(publicId)) {\r
- majorVersion = 2;\r
- minorVersion = 2;\r
- this.publicId = publicId;\r
- } else if ("datatypes".equals(publicId)) {\r
- // Will occur when validation is enabled and dependencies are\r
- // traced back. Ignore it.\r
- } else {\r
- // Unrecognised publicId\r
- log.warn(sm.getString("webxml.unrecognisedPublicId", publicId));\r
- }\r
- }\r
- \r
- // Optional metadata-complete attribute\r
- private boolean metadataComplete = false;\r
- public boolean isMetadataComplete() { return metadataComplete; }\r
- public void setMetadataComplete(boolean metadataComplete) {\r
- this.metadataComplete = metadataComplete; }\r
- \r
- // Optional name element\r
- private String name = null;\r
- public String getName() { return name; }\r
- public void setName(String name) {\r
- if (ORDER_OTHERS.equalsIgnoreCase(name)) {\r
- // This is unusual. This name will be ignored. Log the fact.\r
- log.warn(sm.getString("webXml.reservedName", name));\r
- } else {\r
- this.name = name;\r
- }\r
- }\r
-\r
- // Derived major and minor version attributes\r
- // Default to 3.0 until we know otherwise\r
- private int majorVersion = 3;\r
- private int minorVersion = 0;\r
- public int getMajorVersion() { return majorVersion; }\r
- public int getMinorVersion() { return minorVersion; }\r
- \r
- // web-app elements\r
- // TODO: Ignored elements:\r
- // - description\r
- // - icon\r
-\r
- // display-name - TODO should support multiple with language\r
- private String displayName = null;\r
- public String getDisplayName() { return displayName; }\r
- public void setDisplayName(String displayName) {\r
- this.displayName = displayName;\r
- }\r
- \r
- // distributable\r
- private boolean distributable = false;\r
- public boolean isDistributable() { return distributable; }\r
- public void setDistributable(boolean distributable) {\r
- this.distributable = distributable;\r
- }\r
- \r
- // context-param\r
- // TODO: description (multiple with language) is ignored\r
- private Map<String,String> contextParams = new HashMap<String,String>();\r
- public void addContextParam(String param, String value) {\r
- contextParams.put(param, value);\r
- }\r
- public Map<String,String> getContextParams() { return contextParams; }\r
- \r
- // filter\r
- // TODO: Should support multiple description elements with language\r
- // TODO: Should support multiple display-name elements with language\r
- // TODO: Should support multiple icon elements\r
- // TODO: Description for init-param is ignored\r
- private Map<String,FilterDef> filters =\r
- new LinkedHashMap<String,FilterDef>();\r
- public void addFilter(FilterDef filter) {\r
- if (filters.containsKey(filter.getFilterName())) {\r
- // Filter names must be unique within a web(-fragment).xml\r
- throw new IllegalArgumentException(\r
- sm.getString("webXml.duplicateFilter",\r
- filter.getFilterName()));\r
- }\r
- filters.put(filter.getFilterName(), filter);\r
- }\r
- public Map<String,FilterDef> getFilters() { return filters; }\r
- \r
- // filter-mapping\r
- private Set<FilterMap> filterMaps = new LinkedHashSet<FilterMap>();\r
- private Set<String> filterMappingNames = new HashSet<String>();\r
- public void addFilterMapping(FilterMap filterMap) {\r
- filterMaps.add(filterMap);\r
- filterMappingNames.add(filterMap.getFilterName());\r
- }\r
- public Set<FilterMap> getFilterMappings() { return filterMaps; }\r
- \r
- // listener\r
- // TODO: description (multiple with language) is ignored\r
- // TODO: display-name (multiple with language) is ignored\r
- // TODO: icon (multiple) is ignored\r
- private Set<String> listeners = new LinkedHashSet<String>();\r
- public void addListener(String className) {\r
- listeners.add(className);\r
- }\r
- public Set<String> getListeners() { return listeners; }\r
- \r
- // servlet\r
- // TODO: description (multiple with language) is ignored\r
- // TODO: display-name (multiple with language) is ignored\r
- // TODO: icon (multiple) is ignored\r
- // TODO: init-param/description (multiple with language) is ignored\r
- // TODO: security-role-ref/description (multiple with language) is ignored\r
- private Map<String,ServletDef> servlets = new HashMap<String,ServletDef>();\r
- public void addServlet(ServletDef servletDef) {\r
- servlets.put(servletDef.getServletName(), servletDef);\r
- if (overridable) {\r
- servletDef.setOverridable(overridable);\r
- }\r
- }\r
- public Map<String,ServletDef> getServlets() { return servlets; }\r
- \r
- // servlet-mapping\r
- private Map<String,String> servletMappings = new HashMap<String,String>();\r
- private Set<String> servletMappingNames = new HashSet<String>();\r
- public void addServletMapping(String urlPattern, String servletName) {\r
- servletMappings.put(urlPattern, servletName);\r
- servletMappingNames.add(servletName);\r
- }\r
- public Map<String,String> getServletMappings() { return servletMappings; }\r
- \r
- // session-config\r
- // Digester will check there is only one of these\r
- private SessionConfig sessionConfig = new SessionConfig();\r
- public void setSessionConfig(SessionConfig sessionConfig) {\r
- this.sessionConfig = sessionConfig;\r
- }\r
- public SessionConfig getSessionConfig() { return sessionConfig; }\r
- \r
- // mime-mapping\r
- private Map<String,String> mimeMappings = new HashMap<String,String>();\r
- public void addMimeMapping(String extension, String mimeType) {\r
- mimeMappings.put(extension, mimeType);\r
- }\r
- public Map<String,String> getMimeMappings() { return mimeMappings; }\r
- \r
- // welcome-file-list merge control\r
- private boolean replaceWelcomeFiles = false;\r
- private boolean alwaysAddWelcomeFiles = true;\r
- /**\r
- * When merging/parsing web.xml files into this web.xml should the current\r
- * set be completely replaced?\r
- */\r
- public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) {\r
- this.replaceWelcomeFiles = replaceWelcomeFiles;\r
- }\r
- /**\r
- * When merging from this web.xml, should the welcome files be added to the\r
- * target web.xml even if it already contains welcome file definitions.\r
- */\r
- public void setAlwaysAddWelcomeFiles(boolean alwaysAddWelcomeFiles) {\r
- this.alwaysAddWelcomeFiles = alwaysAddWelcomeFiles;\r
- }\r
-\r
- // welcome-file-list\r
- private Set<String> welcomeFiles = new LinkedHashSet<String>();\r
- public void addWelcomeFile(String welcomeFile) {\r
- if (replaceWelcomeFiles) {\r
- welcomeFiles.clear();\r
- replaceWelcomeFiles = false;\r
- }\r
- welcomeFiles.add(welcomeFile);\r
- }\r
- public Set<String> getWelcomeFiles() { return welcomeFiles; }\r
- \r
- // error-page\r
- private Map<String,ErrorPage> errorPages = new HashMap<String,ErrorPage>();\r
- public void addErrorPage(ErrorPage errorPage) {\r
- errorPages.put(errorPage.getName(), errorPage);\r
- }\r
- public Map<String,ErrorPage> getErrorPages() { return errorPages; }\r
- \r
- // Digester will check there is only one jsp-config\r
- // jsp-config/taglib or taglib (2.3 and earlier)\r
- private Map<String,String> taglibs = new HashMap<String,String>();\r
- public void addTaglib(String uri, String location) {\r
- if (taglibs.containsKey(uri)) {\r
- // Taglib URIs must be unique within a web(-fragment).xml\r
- throw new IllegalArgumentException(\r
- sm.getString("webXml.duplicateTaglibUri", uri));\r
- }\r
- taglibs.put(uri, location);\r
- }\r
- public Map<String,String> getTaglibs() { return taglibs; }\r
- \r
- // jsp-config/jsp-property-group\r
- private Set<JspPropertyGroup> jspPropertyGroups =\r
- new HashSet<JspPropertyGroup>();\r
- public void addJspPropertyGroup(JspPropertyGroup propertyGroup) {\r
- jspPropertyGroups.add(propertyGroup);\r
- }\r
- public Set<JspPropertyGroup> getJspPropertyGroups() {\r
- return jspPropertyGroups;\r
- }\r
-\r
- // security-constraint\r
- // TODO: Should support multiple display-name elements with language\r
- // TODO: Should support multiple description elements with language\r
- private Set<SecurityConstraint> securityConstraints =\r
- new HashSet<SecurityConstraint>();\r
- public void addSecurityConstraint(SecurityConstraint securityConstraint) {\r
- securityConstraints.add(securityConstraint);\r
- }\r
- public Set<SecurityConstraint> getSecurityConstraints() {\r
- return securityConstraints;\r
- }\r
- \r
- // login-config\r
- // Digester will check there is only one of these\r
- private LoginConfig loginConfig = null;\r
- public void setLoginConfig(LoginConfig loginConfig) {\r
- this.loginConfig = loginConfig;\r
- }\r
- public LoginConfig getLoginConfig() { return loginConfig; }\r
- \r
- // security-role\r
- // TODO: description (multiple with language) is ignored\r
- private Set<String> securityRoles = new HashSet<String>();\r
- public void addSecurityRole(String securityRole) {\r
- securityRoles.add(securityRole);\r
- }\r
- public Set<String> getSecurityRoles() { return securityRoles; }\r
- \r
- // env-entry\r
- // TODO: Should support multiple description elements with language\r
- private Map<String,ContextEnvironment> envEntries =\r
- new HashMap<String,ContextEnvironment>();\r
- public void addEnvEntry(ContextEnvironment envEntry) {\r
- if (envEntries.containsKey(envEntry.getName())) {\r
- // env-entry names must be unique within a web(-fragment).xml\r
- throw new IllegalArgumentException(\r
- sm.getString("webXml.duplicateEnvEntry",\r
- envEntry.getName()));\r
- }\r
- envEntries.put(envEntry.getName(),envEntry);\r
- }\r
- public Map<String,ContextEnvironment> getEnvEntries() { return envEntries; }\r
- \r
- // ejb-ref\r
- // TODO: Should support multiple description elements with language\r
- private Map<String,ContextEjb> ejbRefs = new HashMap<String,ContextEjb>();\r
- public void addEjbRef(ContextEjb ejbRef) {\r
- ejbRefs.put(ejbRef.getName(),ejbRef);\r
- }\r
- public Map<String,ContextEjb> getEjbRefs() { return ejbRefs; }\r
- \r
- // ejb-local-ref\r
- // TODO: Should support multiple description elements with language\r
- private Map<String,ContextLocalEjb> ejbLocalRefs =\r
- new HashMap<String,ContextLocalEjb>();\r
- public void addEjbLocalRef(ContextLocalEjb ejbLocalRef) {\r
- ejbLocalRefs.put(ejbLocalRef.getName(),ejbLocalRef);\r
- }\r
- public Map<String,ContextLocalEjb> getEjbLocalRefs() {\r
- return ejbLocalRefs;\r
- }\r
- \r
- // service-ref\r
- // TODO: Should support multiple description elements with language\r
- // TODO: Should support multiple display-names elements with language\r
- // TODO: Should support multiple icon elements ???\r
- private Map<String,ContextService> serviceRefs =\r
- new HashMap<String,ContextService>();\r
- public void addServiceRef(ContextService serviceRef) {\r
- serviceRefs.put(serviceRef.getName(), serviceRef);\r
- }\r
- public Map<String,ContextService> getServiceRefs() { return serviceRefs; }\r
- \r
- // resource-ref\r
- // TODO: Should support multiple description elements with language\r
- private Map<String,ContextResource> resourceRefs =\r
- new HashMap<String,ContextResource>();\r
- public void addResourceRef(ContextResource resourceRef) {\r
- if (resourceRefs.containsKey(resourceRef.getName())) {\r
- // resource-ref names must be unique within a web(-fragment).xml\r
- throw new IllegalArgumentException(\r
- sm.getString("webXml.duplicateResourceRef",\r
- resourceRef.getName()));\r
- }\r
- resourceRefs.put(resourceRef.getName(), resourceRef);\r
- }\r
- public Map<String,ContextResource> getResourceRefs() {\r
- return resourceRefs;\r
- }\r
- \r
- // resource-env-ref\r
- // TODO: Should support multiple description elements with language\r
- private Map<String,ContextResourceEnvRef> resourceEnvRefs =\r
- new HashMap<String,ContextResourceEnvRef>();\r
- public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) {\r
- if (resourceEnvRefs.containsKey(resourceEnvRef.getName())) {\r
- // resource-env-ref names must be unique within a web(-fragment).xml\r
- throw new IllegalArgumentException(\r
- sm.getString("webXml.duplicateResourceEnvRef",\r
- resourceEnvRef.getName()));\r
- }\r
- resourceEnvRefs.put(resourceEnvRef.getName(), resourceEnvRef);\r
- }\r
- public Map<String,ContextResourceEnvRef> getResourceEnvRefs() {\r
- return resourceEnvRefs;\r
- }\r
- \r
- // message-destination-ref\r
- // TODO: Should support multiple description elements with language\r
- private Map<String,MessageDestinationRef> messageDestinationRefs =\r
- new HashMap<String,MessageDestinationRef>();\r
- public void addMessageDestinationRef(\r
- MessageDestinationRef messageDestinationRef) {\r
- if (messageDestinationRefs.containsKey(\r
- messageDestinationRef.getName())) {\r
- // message-destination-ref names must be unique within a\r
- // web(-fragment).xml\r
- throw new IllegalArgumentException(sm.getString(\r
- "webXml.duplicateMessageDestinationRef",\r
- messageDestinationRef.getName()));\r
- }\r
- messageDestinationRefs.put(messageDestinationRef.getName(),\r
- messageDestinationRef);\r
- }\r
- public Map<String,MessageDestinationRef> getMessageDestinationRefs() {\r
- return messageDestinationRefs;\r
- }\r
- \r
- // message-destination\r
- // TODO: Should support multiple description elements with language\r
- // TODO: Should support multiple display-names elements with language\r
- // TODO: Should support multiple icon elements ???\r
- private Map<String,MessageDestination> messageDestinations =\r
- new HashMap<String,MessageDestination>();\r
- public void addMessageDestination(\r
- MessageDestination messageDestination) {\r
- if (messageDestinations.containsKey(\r
- messageDestination.getName())) {\r
- // message-destination names must be unique within a\r
- // web(-fragment).xml\r
- throw new IllegalArgumentException(\r
- sm.getString("webXml.duplicateMessageDestination",\r
- messageDestination.getName()));\r
- }\r
- messageDestinations.put(messageDestination.getName(),\r
- messageDestination);\r
- }\r
- public Map<String,MessageDestination> getMessageDestinations() {\r
- return messageDestinations;\r
- }\r
- \r
- // locale-encoging-mapping-list\r
- private Map<String,String> localeEncodingMappings =\r
- new HashMap<String,String>();\r
- public void addLocaleEncodingMapping(String locale, String encoding) {\r
- localeEncodingMappings.put(locale, encoding);\r
- }\r
- public Map<String,String> getLocalEncodingMappings() {\r
- return localeEncodingMappings;\r
- }\r
- \r
-\r
- // Attributes not defined in web.xml or web-fragment.xml\r
- \r
- // URL of JAR / exploded JAR for this web-fragment\r
- private URL uRL = null;\r
- public void setURL(URL url) { this.uRL = url; }\r
- public URL getURL() { return uRL; }\r
-\r
-\r
- @Override\r
- public String toString() {\r
- StringBuilder buf = new StringBuilder(32);\r
- buf.append("Name: ");\r
- buf.append(getName());\r
- buf.append(", URL: ");\r
- buf.append(getURL());\r
- return buf.toString();\r
- }\r
- \r
- private static final String INDENT2 = " ";\r
- private static final String INDENT4 = " ";\r
- private static final String INDENT6 = " ";\r
- \r
- /**\r
- * Generate a web.xml in String form that matches the representation stored\r
- * in this object.\r
- * \r
- * @return The complete contents of web.xml as a String\r
- */\r
- public String toXml() {\r
- StringBuilder sb = new StringBuilder(2048);\r
- \r
- // TODO - Various, icon, description etc elements are skipped - mainly\r
- // because they are ignored when web.xml is parsed - see above\r
-\r
- // Declaration\r
- sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");\r
- \r
- // Root element\r
- sb.append("<web-app xmlns=\"http://java.sun.com/xml/ns/javaee\"\n");\r
- sb.append(" xmlns:xsi=");\r
- sb.append("\"http://www.w3.org/2001/XMLSchema-instance\"\n");\r
- sb.append(" xsi:schemaLocation=");\r
- sb.append("\"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\"\n");\r
- sb.append(" version=\"");\r
- sb.append(getVersion());\r
- sb.append("\"\n");\r
- sb.append(" metadata-complete=\"true\">\n\n");\r
-\r
- appendElement(sb, INDENT2, "display-name", displayName);\r
- \r
- if (isDistributable()) {\r
- sb.append(" <distributable/>\n\n");\r
- }\r
- \r
- for (Map.Entry<String, String> entry : contextParams.entrySet()) {\r
- sb.append(" <context-param>\n");\r
- appendElement(sb, INDENT4, "param-name", entry.getKey());\r
- appendElement(sb, INDENT4, "param-valuee", entry.getValue());\r
- sb.append(" </context-param>\n");\r
- }\r
- sb.append('\n');\r
- \r
- for (Map.Entry<String, FilterDef> entry : filters.entrySet()) {\r
- FilterDef filterDef = entry.getValue();\r
- sb.append(" <filter>\n");\r
- appendElement(sb, INDENT4, "description",\r
- filterDef.getDescription());\r
- appendElement(sb, INDENT4, "display-name",\r
- filterDef.getDisplayName());\r
- appendElement(sb, INDENT4, "filter-name",\r
- filterDef.getFilterName());\r
- appendElement(sb, INDENT4, "filter-class",\r
- filterDef.getFilterClass());\r
- appendElement(sb, INDENT4, "async-supported",\r
- filterDef.getAsyncSupported());\r
- for (Map.Entry<String, String> param :\r
- filterDef.getParameterMap().entrySet()) {\r
- sb.append(" <init-param>\n");\r
- appendElement(sb, INDENT6, "param-name", param.getKey());\r
- appendElement(sb, INDENT6, "param-value", param.getValue());\r
- sb.append(" </init-param>\n");\r
- }\r
- sb.append(" </filter>\n");\r
- }\r
- sb.append('\n');\r
-\r
- for (FilterMap filterMap : filterMaps) {\r
- sb.append(" <filter-mapping>\n");\r
- appendElement(sb, INDENT4, "filter-name",\r
- filterMap.getFilterName());\r
- if (filterMap.getMatchAllServletNames()) {\r
- sb.append(" <servlet-name>*</servlet-name>\n");\r
- } else {\r
- for (String servletName : filterMap.getServletNames()) {\r
- appendElement(sb, INDENT4, "servlet-name", servletName);\r
- }\r
- }\r
- if (filterMap.getMatchAllUrlPatterns()) {\r
- sb.append(" <url-pattern>*</url-pattern>\n");\r
- } else {\r
- for (String urlPattern : filterMap.getURLPatterns()) {\r
- appendElement(sb, INDENT4, "url-pattern", urlPattern);\r
- }\r
- }\r
- for (String dispatcher : filterMap.getDispatcherNames()) {\r
- appendElement(sb, INDENT4, "dispatcher", dispatcher);\r
- }\r
- sb.append(" </filter-mapping>\n");\r
- }\r
- sb.append('\n');\r
-\r
- for (String listener : listeners) {\r
- sb.append(" <listener>\n");\r
- appendElement(sb, INDENT4, "listener-class", listener);\r
- sb.append(" </listener>\n");\r
- }\r
- sb.append('\n');\r
-\r
- for (Map.Entry<String, ServletDef> entry : servlets.entrySet()) {\r
- ServletDef servletDef = entry.getValue();\r
- sb.append(" <servlet>\n");\r
- appendElement(sb, INDENT4, "description",\r
- servletDef.getDescription());\r
- appendElement(sb, INDENT4, "display-name",\r
- servletDef.getDisplayName());\r
- appendElement(sb, INDENT4, "servlet-name", entry.getKey());\r
- appendElement(sb, INDENT4, "servlet-class",\r
- servletDef.getServletClass());\r
- appendElement(sb, INDENT4, "jsp-file", servletDef.getJspFile());\r
- for (Map.Entry<String, String> param :\r
- servletDef.getParameterMap().entrySet()) {\r
- sb.append(" <init-param>\n");\r
- appendElement(sb, INDENT6, "param-name", param.getKey());\r
- appendElement(sb, INDENT6, "param-value", param.getValue());\r
- sb.append(" </init-param>\n");\r
- }\r
- appendElement(sb, INDENT4, "load-on-startup",\r
- servletDef.getLoadOnStartup());\r
- appendElement(sb, INDENT4, "enabled", servletDef.getEnabled());\r
- appendElement(sb, INDENT4, "async-supported",\r
- servletDef.getAsyncSupported());\r
- if (servletDef.getRunAs() != null) {\r
- sb.append(" <run-as>\n");\r
- appendElement(sb, INDENT6, "role-name", servletDef.getRunAs());\r
- sb.append(" </run-as>\n");\r
- }\r
- for (SecurityRoleRef roleRef : servletDef.getSecurityRoleRefs()) {\r
- sb.append(" <security-role-ref>\n");\r
- appendElement(sb, INDENT6, "role-name", roleRef.getName());\r
- appendElement(sb, INDENT6, "role-link", roleRef.getLink());\r
- sb.append(" </security-role-ref>\n");\r
- }\r
- MultipartDef multipartDef = servletDef.getMultipartDef();\r
- if (multipartDef != null) {\r
- sb.append(" <multipart-config>\n");\r
- appendElement(sb, INDENT6, "location",\r
- multipartDef.getLocation());\r
- appendElement(sb, INDENT6, "max-file-size",\r
- multipartDef.getMaxFileSize());\r
- appendElement(sb, INDENT6, "max-request-size",\r
- multipartDef.getMaxRequestSize());\r
- appendElement(sb, INDENT6, "file-size-threshold",\r
- multipartDef.getFileSizeThreshold());\r
- sb.append(" </multipart-config>\n");\r
- }\r
- sb.append(" </servlet>\n");\r
- }\r
- sb.append('\n');\r
-\r
- for (Map.Entry<String, String> entry : servletMappings.entrySet()) {\r
- sb.append(" <servlet-mapping>\n");\r
- appendElement(sb, INDENT4, "servlet-name", entry.getValue());\r
- appendElement(sb, INDENT4, "url-pattern", entry.getKey());\r
- sb.append(" </servlet-mapping>\n");\r
- }\r
- sb.append('\n');\r
- \r
- if (sessionConfig != null) {\r
- sb.append(" <session-config>\n");\r
- appendElement(sb, INDENT4, "session-timeout",\r
- sessionConfig.getSessionTimeout());\r
- sb.append(" <cookie-config>\n");\r
- appendElement(sb, INDENT6, "name", sessionConfig.getCookieName());\r
- appendElement(sb, INDENT6, "domain",\r
- sessionConfig.getCookieDomain());\r
- appendElement(sb, INDENT6, "path", sessionConfig.getCookiePath());\r
- appendElement(sb, INDENT6, "comment",\r
- sessionConfig.getCookieComment());\r
- appendElement(sb, INDENT6, "http-only",\r
- sessionConfig.getCookieHttpOnly());\r
- appendElement(sb, INDENT6, "secure",\r
- sessionConfig.getCookieSecure());\r
- appendElement(sb, INDENT6, "max-age",\r
- sessionConfig.getCookieMaxAge());\r
- sb.append(" </cookie-config>\n");\r
- for (SessionTrackingMode stm :\r
- sessionConfig.getSessionTrackingModes()) {\r
- appendElement(sb, INDENT4, "tracking-mode", stm.name());\r
- }\r
- sb.append(" </session-config>\n\n");\r
- }\r
- \r
- for (Map.Entry<String, String> entry : mimeMappings.entrySet()) {\r
- sb.append(" <mime-mapping>\n");\r
- appendElement(sb, INDENT4, "extension", entry.getKey());\r
- appendElement(sb, INDENT4, "mime-type", entry.getValue());\r
- sb.append(" </mime-mapping>\n");\r
- }\r
- sb.append('\n');\r
- \r
- if (welcomeFiles.size() > 0) {\r
- sb.append(" <welcome-file-list>\n");\r
- for (String welcomeFile : welcomeFiles) {\r
- appendElement(sb, INDENT4, "welcome-file", welcomeFile);\r
- }\r
- sb.append(" </welcome-file-list>\n\n");\r
- }\r
- \r
- for (ErrorPage errorPage : errorPages.values()) {\r
- sb.append(" <error-page>\n");\r
- if (errorPage.getExceptionType() == null) {\r
- appendElement(sb, INDENT4, "error-code",\r
- Integer.toString(errorPage.getErrorCode()));\r
- } else {\r
- appendElement(sb, INDENT4, "exception-type",\r
- errorPage.getExceptionType());\r
- }\r
- appendElement(sb, INDENT4, "location", errorPage.getLocation());\r
- sb.append(" </error-page>\n");\r
- }\r
- sb.append('\n');\r
-\r
- if (taglibs.size() > 0 || jspPropertyGroups.size() > 0) {\r
- sb.append(" <jsp-config>\n");\r
- for (Map.Entry<String, String> entry : taglibs.entrySet()) {\r
- sb.append(" <taglib>\n");\r
- appendElement(sb, INDENT6, "taglib-uri", entry.getKey());\r
- appendElement(sb, INDENT6, "taglib-location", entry.getValue());\r
- sb.append(" </taglib>\n");\r
- }\r
- for (JspPropertyGroup jpg : jspPropertyGroups) {\r
- sb.append(" <jsp-property-group>\n");\r
- appendElement(sb, INDENT6, "url-pattern", jpg.getUrlPattern());\r
- appendElement(sb, INDENT6, "el-ignored", jpg.getElIgnored());\r
- appendElement(sb, INDENT6, "scripting-invalid",\r
- jpg.getScriptingInvalid());\r
- appendElement(sb, INDENT6, "page-encoding",\r
- jpg.getPageEncoding());\r
- for (String prelude : jpg.getIncludePreludes()) {\r
- appendElement(sb, INDENT6, "include-prelude", prelude);\r
- }\r
- for (String coda : jpg.getIncludeCodas()) {\r
- appendElement(sb, INDENT6, "include-coda", coda);\r
- }\r
- appendElement(sb, INDENT6, "is-xml", jpg.getIsXml());\r
- appendElement(sb, INDENT6, "deferred-syntax-allowed-as-literal",\r
- jpg.getDeferredSyntax());\r
- appendElement(sb, INDENT6, "trim-directive-whitespaces",\r
- jpg.getTrimWhitespace());\r
- appendElement(sb, INDENT6, "default-content-type",\r
- jpg.getDefaultContentType());\r
- appendElement(sb, INDENT6, "buffer", jpg.getBuffer());\r
- appendElement(sb, INDENT6, "error-on-undeclared-namespace",\r
- jpg.getErrorOnUndeclaredNamespace());\r
- sb.append(" </jsp-property-group>\n");\r
- }\r
- sb.append(" </jsp-config>\n\n");\r
- }\r
- \r
- for (SecurityConstraint constraint : securityConstraints) {\r
- sb.append(" <security-constraint>\n");\r
- appendElement(sb, INDENT4, "display-name",\r
- constraint.getDisplayName());\r
- for (SecurityCollection collection : constraint.findCollections()) {\r
- sb.append(" <web-resource-collection>\n");\r
- appendElement(sb, INDENT6, "web-resource-name",\r
- collection.getName());\r
- appendElement(sb, INDENT6, "description",\r
- collection.getDescription());\r
- for (String urlPattern : collection.findPatterns()) {\r
- appendElement(sb, INDENT6, "url-pattern", urlPattern);\r
- }\r
- for (String method : collection.findMethods()) {\r
- appendElement(sb, INDENT6, "http-method", method);\r
- }\r
- for (String method : collection.findOmittedMethods()) {\r
- appendElement(sb, INDENT6, "http-method-omission", method);\r
- }\r
- sb.append(" </web-resource-collection>\n");\r
- }\r
- if (constraint.findAuthRoles().length > 0) {\r
- sb.append(" <auth-constraint>\n");\r
- for (String role : constraint.findAuthRoles()) {\r
- appendElement(sb, INDENT6, "role-name", role);\r
- }\r
- sb.append(" </auth-constraint>\n");\r
- }\r
- if (constraint.getUserConstraint() != null) {\r
- sb.append(" <user-data-constraint>\n");\r
- appendElement(sb, INDENT6, "transport-guarantee",\r
- constraint.getUserConstraint());\r
- sb.append(" </user-data-constraint>\n");\r
- }\r
- sb.append(" </security-constraint>\n");\r
- }\r
- sb.append('\n');\r
-\r
- if (loginConfig != null) {\r
- sb.append(" <login-config>\n");\r
- appendElement(sb, INDENT4, "auth-method",\r
- loginConfig.getAuthMethod());\r
- appendElement(sb,INDENT4, "realm-name",\r
- loginConfig.getRealmName());\r
- if (loginConfig.getErrorPage() != null ||\r
- loginConfig.getLoginPage() != null) {\r
- sb.append(" <form-login-config>\n");\r
- appendElement(sb, INDENT6, "form-login-page",\r
- loginConfig.getLoginPage());\r
- appendElement(sb, INDENT6, "form-error-page",\r
- loginConfig.getErrorPage());\r
- sb.append(" </form-login-config>\n");\r
- }\r
- sb.append(" </login-config>\n\n");\r
- }\r
- \r
- for (String roleName : securityRoles) {\r
- sb.append(" <security-role>\n");\r
- appendElement(sb, INDENT4, "role-name", roleName);\r
- sb.append(" </security-role>\n");\r
- }\r
- \r
- for (ContextEnvironment envEntry : envEntries.values()) {\r
- sb.append(" <env-entry>\n");\r
- appendElement(sb, INDENT4, "description",\r
- envEntry.getDescription());\r
- appendElement(sb, INDENT4, "env-entry-name", envEntry.getName());\r
- appendElement(sb, INDENT4, "env-entry-type", envEntry.getType());\r
- appendElement(sb, INDENT4, "env-entry-value", envEntry.getValue());\r
- // TODO mapped-name\r
- for (InjectionTarget target : envEntry.getInjectionTargets()) {\r
- sb.append(" <injection-target>\n");\r
- appendElement(sb, INDENT6, "injection-target-class",\r
- target.getTargetClass());\r
- appendElement(sb, INDENT6, "injection-target-name",\r
- target.getTargetName());\r
- sb.append(" </injection-target>\n");\r
- }\r
- // TODO lookup-name\r
- sb.append(" </env-entry>\n");\r
- }\r
- sb.append('\n');\r
-\r
- for (ContextEjb ejbRef : ejbRefs.values()) {\r
- sb.append(" <ejb-ref>\n");\r
- appendElement(sb, INDENT4, "description", ejbRef.getDescription());\r
- appendElement(sb, INDENT4, "ejb-ref-name", ejbRef.getName());\r
- appendElement(sb, INDENT4, "ejb-ref-type", ejbRef.getType());\r
- appendElement(sb, INDENT4, "home", ejbRef.getHome());\r
- appendElement(sb, INDENT4, "remote", ejbRef.getRemote());\r
- appendElement(sb, INDENT4, "ejb-link", ejbRef.getLink());\r
- // TODO mapped-name\r
- for (InjectionTarget target : ejbRef.getInjectionTargets()) {\r
- sb.append(" <injection-target>\n");\r
- appendElement(sb, INDENT6, "injection-target-class",\r
- target.getTargetClass());\r
- appendElement(sb, INDENT6, "injection-target-name",\r
- target.getTargetName());\r
- sb.append(" </injection-target>\n");\r
- }\r
- // TODO lookup-name\r
- sb.append(" </ejb-ref>\n");\r
- }\r
- sb.append('\n');\r
-\r
- for (ContextLocalEjb ejbLocalRef : ejbLocalRefs.values()) {\r
- sb.append(" <ejb-local-ref>\n");\r
- appendElement(sb, INDENT4, "description",\r
- ejbLocalRef.getDescription());\r
- appendElement(sb, INDENT4, "ejb-ref-name", ejbLocalRef.getName());\r
- appendElement(sb, INDENT4, "ejb-ref-type", ejbLocalRef.getType());\r
- appendElement(sb, INDENT4, "local-home", ejbLocalRef.getHome());\r
- appendElement(sb, INDENT4, "local", ejbLocalRef.getLocal());\r
- appendElement(sb, INDENT4, "ejb-link", ejbLocalRef.getLink());\r
- // TODO mapped-name\r
- for (InjectionTarget target : ejbLocalRef.getInjectionTargets()) {\r
- sb.append(" <injection-target>\n");\r
- appendElement(sb, INDENT6, "injection-target-class",\r
- target.getTargetClass());\r
- appendElement(sb, INDENT6, "injection-target-name",\r
- target.getTargetName());\r
- sb.append(" </injection-target>\n");\r
- }\r
- // TODO lookup-name\r
- sb.append(" </ejb-local-ref>\n");\r
- }\r
- sb.append('\n');\r
- \r
- for (ContextService serviceRef : serviceRefs.values()) {\r
- sb.append(" <service-ref>\n");\r
- appendElement(sb, INDENT4, "description",\r
- serviceRef.getDescription());\r
- appendElement(sb, INDENT4, "display-name",\r
- serviceRef.getDisplayname());\r
- appendElement(sb, INDENT4, "service-ref-name",\r
- serviceRef.getName());\r
- appendElement(sb, INDENT4, "service-interface",\r
- serviceRef.getInterface());\r
- appendElement(sb, INDENT4, "service-ref-type",\r
- serviceRef.getType());\r
- appendElement(sb, INDENT4, "wsdl-file", serviceRef.getWsdlfile());\r
- appendElement(sb, INDENT4, "jaxrpc-mapping-file",\r
- serviceRef.getJaxrpcmappingfile());\r
- String qname = serviceRef.getServiceqnameNamespaceURI();\r
- if (qname != null) {\r
- qname = qname + ":";\r
- }\r
- qname = qname + serviceRef.getServiceqnameLocalpart();\r
- appendElement(sb, INDENT4, "service-qname", qname);\r
- Iterator<String> endpointIter = serviceRef.getServiceendpoints();\r
- while (endpointIter.hasNext()) {\r
- String endpoint = endpointIter.next();\r
- sb.append(" <port-component-ref>\n");\r
- appendElement(sb, INDENT6, "service-endpoint-interface",\r
- endpoint);\r
- appendElement(sb, INDENT6, "port-component-link",\r
- serviceRef.getProperty(endpoint));\r
- sb.append(" </port-component-ref>\n");\r
- }\r
- Iterator<String> handlerIter = serviceRef.getHandlers();\r
- while (handlerIter.hasNext()) {\r
- String handler = handlerIter.next();\r
- sb.append(" <handler>\n");\r
- ContextHandler ch = serviceRef.getHandler(handler);\r
- appendElement(sb, INDENT6, "handler-name", ch.getName());\r
- appendElement(sb, INDENT6, "handler-class",\r
- ch.getHandlerclass());\r
- sb.append(" </handler>\n");\r
- }\r
- // TODO handler-chains\r
- // TODO mapped-name\r
- for (InjectionTarget target : serviceRef.getInjectionTargets()) {\r
- sb.append(" <injection-target>\n");\r
- appendElement(sb, INDENT6, "injection-target-class",\r
- target.getTargetClass());\r
- appendElement(sb, INDENT6, "injection-target-name",\r
- target.getTargetName());\r
- sb.append(" </injection-target>\n");\r
- }\r
- // TODO lookup-name\r
- sb.append(" </service-ref>\n");\r
- }\r
- sb.append('\n');\r
- \r
- for (ContextResource resourceRef : resourceRefs.values()) {\r
- sb.append(" <resource-ref>\n");\r
- appendElement(sb, INDENT4, "description",\r
- resourceRef.getDescription());\r
- appendElement(sb, INDENT4, "res-ref-name", resourceRef.getName());\r
- appendElement(sb, INDENT4, "res-type", resourceRef.getType());\r
- appendElement(sb, INDENT4, "res-auth", resourceRef.getAuth());\r
- appendElement(sb, INDENT4, "res-sharing-scope",\r
- resourceRef.getScope());\r
- // TODO mapped-name\r
- for (InjectionTarget target : resourceRef.getInjectionTargets()) {\r
- sb.append(" <injection-target>\n");\r
- appendElement(sb, INDENT6, "injection-target-class",\r
- target.getTargetClass());\r
- appendElement(sb, INDENT6, "injection-target-name",\r
- target.getTargetName());\r
- sb.append(" </injection-target>\n");\r
- }\r
- // TODO lookup-name\r
- sb.append(" </resource-ref>\n");\r
- }\r
- sb.append('\n');\r
-\r
- for (ContextResourceEnvRef resourceEnvRef : resourceEnvRefs.values()) {\r
- sb.append(" <resource-env-ref>\n");\r
- appendElement(sb, INDENT4, "description",\r
- resourceEnvRef.getDescription());\r
- appendElement(sb, INDENT4, "resource-env-ref-name",\r
- resourceEnvRef.getName());\r
- appendElement(sb, INDENT4, "resource-env-ref-type",\r
- resourceEnvRef.getType());\r
- // TODO mapped-name\r
- for (InjectionTarget target :\r
- resourceEnvRef.getInjectionTargets()) {\r
- sb.append(" <injection-target>\n");\r
- appendElement(sb, INDENT6, "injection-target-class",\r
- target.getTargetClass());\r
- appendElement(sb, INDENT6, "injection-target-name",\r
- target.getTargetName());\r
- sb.append(" </injection-target>\n");\r
- }\r
- // TODO lookup-name\r
- sb.append(" </resource-env-ref>\n");\r
- }\r
- sb.append('\n');\r
-\r
- for (MessageDestinationRef mdr : messageDestinationRefs.values()) {\r
- sb.append(" <message-destination-ref>\n");\r
- appendElement(sb, INDENT4, "description", mdr.getDescription());\r
- appendElement(sb, INDENT4, "message-destination-ref-name",\r
- mdr.getName());\r
- appendElement(sb, INDENT4, "message-destination-type",\r
- mdr.getType());\r
- appendElement(sb, INDENT4, "message-destination-usage",\r
- mdr.getUsage());\r
- appendElement(sb, INDENT4, "message-destination-link",\r
- mdr.getLink());\r
- // TODO mapped-name\r
- for (InjectionTarget target : mdr.getInjectionTargets()) {\r
- sb.append(" <injection-target>\n");\r
- appendElement(sb, INDENT6, "injection-target-class",\r
- target.getTargetClass());\r
- appendElement(sb, INDENT6, "injection-target-name",\r
- target.getTargetName());\r
- sb.append(" </injection-target>\n");\r
- }\r
- // TODO lookup-name\r
- sb.append(" </message-destination-ref>\n");\r
- }\r
- sb.append('\n');\r
-\r
- for (MessageDestination md : messageDestinations.values()) {\r
- sb.append(" <message-destination>\n");\r
- appendElement(sb, INDENT4, "description", md.getDescription());\r
- appendElement(sb, INDENT4, "display-name", md.getDisplayName());\r
- appendElement(sb, INDENT4, "message-destination-name",\r
- md.getName());\r
- // TODO mapped-name\r
- sb.append(" </message-destination>\n");\r
- }\r
- sb.append('\n');\r
-\r
- if (localeEncodingMappings.size() > 0) {\r
- sb.append(" <locale-encoding-mapping-list>\n");\r
- for (Map.Entry<String, String> entry :\r
- localeEncodingMappings.entrySet()) {\r
- sb.append(" <locale-encoding-mapping>\n");\r
- appendElement(sb, INDENT6, "locale", entry.getKey());\r
- appendElement(sb, INDENT6, "encoding", entry.getValue());\r
- sb.append(" </locale-encoding-mapping>\n");\r
- }\r
- sb.append(" </locale-encoding-mapping-list>\n");\r
- }\r
- sb.append("</web-app>");\r
- return sb.toString();\r
- }\r
-\r
- private static void appendElement(StringBuilder sb, String indent,\r
- String elementName, String value) {\r
- if (value == null || value.length() == 0) return;\r
- sb.append(indent);\r
- sb.append('<');\r
- sb.append(elementName);\r
- sb.append('>');\r
- sb.append(escapeXml(value));\r
- sb.append("</");\r
- sb.append(elementName);\r
- sb.append(">\n");\r
- }\r
-\r
- private static void appendElement(StringBuilder sb, String indent,\r
- String elementName, Object value) {\r
- if (value == null) return;\r
- appendElement(sb, indent, elementName, value.toString());\r
- }\r
-\r
-\r
- /**\r
- * Escape the 5 entities defined by XML.\r
- */\r
- private static String escapeXml(String s) {\r
- if (s == null)\r
- return null;\r
- StringBuilder sb = new StringBuilder();\r
- for (int i = 0; i < s.length(); i++) {\r
- char c = s.charAt(i);\r
- if (c == '<') {\r
- sb.append("<");\r
- } else if (c == '>') {\r
- sb.append(">");\r
- } else if (c == '\'') {\r
- sb.append("'");\r
- } else if (c == '&') {\r
- sb.append("&");\r
- } else if (c == '"') {\r
- sb.append(""");\r
- } else {\r
- sb.append(c);\r
- }\r
- }\r
- return sb.toString();\r
- }\r
-\r
-\r
- /**\r
- * Configure a {@link Context} using the stored web.xml representation.\r
- * \r
- * @param context The context to be configured\r
- */\r
- public void configureContext(Context context) {\r
- // As far as possible, process in alphabetical order so it is easy to\r
- // check everything is present\r
- // Some validation depends on correct public ID\r
- context.setPublicId(publicId);\r
-\r
- // Everything else in order\r
- context.setEffectiveMajorVersion(getMajorVersion());\r
- context.setEffectiveMinorVersion(getMinorVersion());\r
- \r
- for (Entry<String, String> entry : contextParams.entrySet()) {\r
- context.addParameter(entry.getKey(), entry.getValue());\r
- }\r
- context.setDisplayName(displayName);\r
- context.setDistributable(distributable);\r
- for (ContextLocalEjb ejbLocalRef : ejbLocalRefs.values()) {\r
- context.getNamingResources().addLocalEjb(ejbLocalRef);\r
- }\r
- for (ContextEjb ejbRef : ejbRefs.values()) {\r
- context.getNamingResources().addEjb(ejbRef);\r
- }\r
- for (ContextEnvironment environment : envEntries.values()) {\r
- context.getNamingResources().addEnvironment(environment);\r
- }\r
- for (ErrorPage errorPage : errorPages.values()) {\r
- context.addErrorPage(errorPage);\r
- }\r
- for (FilterDef filter : filters.values()) {\r
- if (filter.getAsyncSupported() == null) {\r
- filter.setAsyncSupported("false");\r
- }\r
- context.addFilterDef(filter);\r
- }\r
- for (FilterMap filterMap : filterMaps) {\r
- context.addFilterMap(filterMap);\r
- }\r
- for (JspPropertyGroup jspPropertyGroup : jspPropertyGroups) {\r
- JspPropertyGroupDescriptor descriptor =\r
- new ApplicationJspPropertyGroupDescriptor(jspPropertyGroup);\r
- context.getJspConfigDescriptor().getJspPropertyGroups().add(\r
- descriptor);\r
- }\r
- for (String listener : listeners) {\r
- context.addApplicationListener(listener);\r
- }\r
- for (Entry<String, String> entry : localeEncodingMappings.entrySet()) {\r
- context.addLocaleEncodingMappingParameter(entry.getKey(),\r
- entry.getValue());\r
- }\r
- // Prevents IAE\r
- if (loginConfig != null) {\r
- context.setLoginConfig(loginConfig);\r
- }\r
- for (MessageDestinationRef mdr : messageDestinationRefs.values()) {\r
- context.getNamingResources().addMessageDestinationRef(mdr);\r
- }\r
-\r
- // messageDestinations were ignored in Tomcat 6, so ignore here\r
- \r
- context.setIgnoreAnnotations(metadataComplete);\r
- for (Entry<String, String> entry : mimeMappings.entrySet()) {\r
- context.addMimeMapping(entry.getKey(), entry.getValue());\r
- }\r
- // Name is just used for ordering\r
- for (ContextResourceEnvRef resource : resourceEnvRefs.values()) {\r
- context.getNamingResources().addResourceEnvRef(resource);\r
- }\r
- for (ContextResource resource : resourceRefs.values()) {\r
- context.getNamingResources().addResource(resource);\r
- }\r
- for (SecurityConstraint constraint : securityConstraints) {\r
- context.addConstraint(constraint);\r
- }\r
- for (String role : securityRoles) {\r
- context.addSecurityRole(role);\r
- }\r
- for (ContextService service : serviceRefs.values()) {\r
- context.getNamingResources().addService(service);\r
- }\r
- for (ServletDef servlet : servlets.values()) {\r
- Wrapper wrapper = context.createWrapper();\r
- // Description is ignored\r
- // Display name is ignored\r
- // Icons are ignored\r
- \r
- // jsp-file gets passed to the JSP Servlet as an init-param\r
-\r
- if (servlet.getLoadOnStartup() != null) {\r
- wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());\r
- }\r
- if (servlet.getEnabled() != null) {\r
- wrapper.setEnabled(servlet.getEnabled().booleanValue());\r
- }\r
- wrapper.setName(servlet.getServletName());\r
- Map<String,String> params = servlet.getParameterMap(); \r
- for (Entry<String, String> entry : params.entrySet()) {\r
- wrapper.addInitParameter(entry.getKey(), entry.getValue());\r
- }\r
- wrapper.setRunAs(servlet.getRunAs());\r
- Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();\r
- for (SecurityRoleRef roleRef : roleRefs) {\r
- wrapper.addSecurityReference(\r
- roleRef.getName(), roleRef.getLink());\r
- }\r
- wrapper.setServletClass(servlet.getServletClass());\r
- MultipartDef multipartdef = servlet.getMultipartDef();\r
- if (multipartdef != null) {\r
- if (multipartdef.getMaxFileSize() != null &&\r
- multipartdef.getMaxRequestSize()!= null &&\r
- multipartdef.getFileSizeThreshold() != null) {\r
- wrapper.setMultipartConfigElement(new MultipartConfigElement(\r
- multipartdef.getLocation(),\r
- Long.parseLong(multipartdef.getMaxFileSize()),\r
- Long.parseLong(multipartdef.getMaxRequestSize()),\r
- Integer.parseInt(\r
- multipartdef.getFileSizeThreshold())));\r
- } else {\r
- wrapper.setMultipartConfigElement(new MultipartConfigElement(\r
- multipartdef.getLocation()));\r
- }\r
- }\r
- if (servlet.getAsyncSupported() != null) {\r
- wrapper.setAsyncSupported(\r
- servlet.getAsyncSupported().booleanValue());\r
- }\r
- wrapper.setOverridable(servlet.isOverridable());\r
- context.addChild(wrapper);\r
- }\r
- for (Entry<String, String> entry : servletMappings.entrySet()) {\r
- context.addServletMapping(entry.getKey(), entry.getValue());\r
- }\r
- if (sessionConfig != null) {\r
- if (sessionConfig.getSessionTimeout() != null) {\r
- context.setSessionTimeout(\r
- sessionConfig.getSessionTimeout().intValue());\r
- }\r
- SessionCookieConfig scc =\r
- context.getServletContext().getSessionCookieConfig();\r
- scc.setName(sessionConfig.getCookieName());\r
- scc.setDomain(sessionConfig.getCookieDomain());\r
- scc.setPath(sessionConfig.getCookiePath());\r
- scc.setComment(sessionConfig.getCookieComment());\r
- if (sessionConfig.getCookieHttpOnly() != null) {\r
- scc.setHttpOnly(sessionConfig.getCookieHttpOnly().booleanValue());\r
- }\r
- if (sessionConfig.getCookieSecure() != null) {\r
- scc.setSecure(sessionConfig.getCookieSecure().booleanValue());\r
- }\r
- if (sessionConfig.getCookieMaxAge() != null) {\r
- scc.setMaxAge(sessionConfig.getCookieMaxAge().intValue());\r
- }\r
- if (sessionConfig.getSessionTrackingModes().size() > 0) {\r
- context.getServletContext().setSessionTrackingModes(\r
- sessionConfig.getSessionTrackingModes());\r
- }\r
- }\r
- for (Entry<String, String> entry : taglibs.entrySet()) {\r
- TaglibDescriptor descriptor = new ApplicationTaglibDescriptor(\r
- entry.getValue(), entry.getKey());\r
- context.getJspConfigDescriptor().getTaglibs().add(descriptor);\r
- }\r
- \r
- // Context doesn't use version directly\r
- \r
- for (String welcomeFile : welcomeFiles) {\r
- /*\r
- * The following will result in a welcome file of "" so don't add\r
- * that to the context \r
- * <welcome-file-list>\r
- * <welcome-file/>\r
- * </welcome-file-list>\r
- */\r
- if (welcomeFile != null && welcomeFile.length() > 0) {\r
- context.addWelcomeFile(welcomeFile);\r
- }\r
- }\r
-\r
- // Do this last as it depends on servlets\r
- for (JspPropertyGroup jspPropertyGroup : jspPropertyGroups) {\r
- String jspServletName = context.findServletMapping("*.jsp");\r
- if (jspServletName == null) {\r
- jspServletName = "jsp";\r
- }\r
- if (context.findChild(jspServletName) != null) {\r
- context.addServletMapping(jspPropertyGroup.getUrlPattern(),\r
- jspServletName, true);\r
- } else {\r
- if(log.isDebugEnabled())\r
- log.debug("Skiping " + jspPropertyGroup.getUrlPattern() +\r
- " , no servlet " + jspServletName);\r
- }\r
- }\r
- }\r
- \r
- /**\r
- * Merge the supplied web fragments into this main web.xml.\r
- * \r
- * @param fragments The fragments to merge in\r
- * @return <code>true</code> if merge is successful, else\r
- * <code>false</code>\r
- */\r
- public boolean merge(Set<WebXml> fragments) {\r
- // As far as possible, process in alphabetical order so it is easy to\r
- // check everything is present\r
- \r
- // Merge rules vary from element to element. See SRV.8.2.3\r
-\r
- WebXml temp = new WebXml();\r
- Map<String,Boolean> mergeInjectionFlags =\r
- new HashMap<String, Boolean>();\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeMap(fragment.getContextParams(), contextParams,\r
- temp.getContextParams(), fragment, "Context Parameter")) {\r
- return false;\r
- }\r
- }\r
- contextParams.putAll(temp.getContextParams());\r
-\r
- if (displayName == null) {\r
- for (WebXml fragment : fragments) {\r
- String value = fragment.getDisplayName(); \r
- if (value != null) {\r
- if (temp.getDisplayName() == null) {\r
- temp.setDisplayName(value);\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictDisplayName",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- displayName = temp.getDisplayName();\r
- }\r
-\r
- if (distributable) {\r
- for (WebXml fragment : fragments) {\r
- if (!fragment.isDistributable()) {\r
- distributable = false;\r
- break;\r
- }\r
- }\r
- }\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeResourceMap(fragment.getEjbLocalRefs(), ejbLocalRefs,\r
- temp.getEjbLocalRefs(), mergeInjectionFlags, fragment)) {\r
- return false;\r
- }\r
- }\r
- ejbLocalRefs.putAll(temp.getEjbLocalRefs());\r
- mergeInjectionFlags.clear();\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeResourceMap(fragment.getEjbRefs(), ejbRefs,\r
- temp.getEjbRefs(), mergeInjectionFlags, fragment)) {\r
- return false;\r
- }\r
- }\r
- ejbRefs.putAll(temp.getEjbRefs());\r
- mergeInjectionFlags.clear();\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeResourceMap(fragment.getEnvEntries(), envEntries,\r
- temp.getEnvEntries(), mergeInjectionFlags, fragment)) {\r
- return false;\r
- }\r
- }\r
- envEntries.putAll(temp.getEnvEntries());\r
- mergeInjectionFlags.clear();\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeMap(fragment.getErrorPages(), errorPages,\r
- temp.getErrorPages(), fragment, "Error Page")) {\r
- return false;\r
- }\r
- }\r
- errorPages.putAll(temp.getErrorPages());\r
-\r
- // As per 'clarification' from the Servlet EG, filter definitions in the\r
- // main web.xml override those in fragments and those in fragments\r
- // override those in annotations\r
- List<FilterMap> filterMapsToAdd = new ArrayList<FilterMap>();\r
- for (WebXml fragment : fragments) {\r
- for (FilterMap filterMap : fragment.getFilterMappings()) {\r
- if (!filterMappingNames.contains(filterMap.getFilterName())) {\r
- filterMapsToAdd.add(filterMap);\r
- }\r
- }\r
- }\r
- for (FilterMap filterMap : filterMapsToAdd) {\r
- // Additive\r
- addFilterMapping(filterMap);\r
- }\r
-\r
- for (WebXml fragment : fragments) {\r
- for (Map.Entry<String,FilterDef> entry :\r
- fragment.getFilters().entrySet()) {\r
- if (filters.containsKey(entry.getKey())) {\r
- mergeFilter(entry.getValue(),\r
- filters.get(entry.getKey()), false);\r
- } else {\r
- if (temp.getFilters().containsKey(entry.getKey())) {\r
- if (!(mergeFilter(entry.getValue(),\r
- temp.getFilters().get(entry.getKey()), true))) {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictFilter",\r
- entry.getKey(),\r
- fragment.getName(),\r
- fragment.getURL()));\r
- \r
- return false;\r
- }\r
- } else {\r
- temp.getFilters().put(entry.getKey(), entry.getValue());\r
- }\r
- }\r
- }\r
- }\r
- filters.putAll(temp.getFilters());\r
-\r
- for (WebXml fragment : fragments) {\r
- for (JspPropertyGroup jspPropertyGroup :\r
- fragment.getJspPropertyGroups()) {\r
- // Always additive\r
- addJspPropertyGroup(jspPropertyGroup);\r
- }\r
- }\r
-\r
- for (WebXml fragment : fragments) {\r
- for (String listener : fragment.getListeners()) {\r
- // Always additive\r
- addListener(listener);\r
- }\r
- }\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeMap(fragment.getLocalEncodingMappings(),\r
- localeEncodingMappings, temp.getLocalEncodingMappings(),\r
- fragment, "Locale Encoding Mapping")) {\r
- return false;\r
- }\r
- }\r
- localeEncodingMappings.putAll(temp.getLocalEncodingMappings());\r
-\r
- if (getLoginConfig() == null) {\r
- LoginConfig tempLoginConfig = null;\r
- for (WebXml fragment : fragments) {\r
- LoginConfig fragmentLoginConfig = fragment.loginConfig;\r
- if (fragmentLoginConfig != null) {\r
- if (tempLoginConfig == null ||\r
- fragmentLoginConfig.equals(tempLoginConfig)) {\r
- tempLoginConfig = fragmentLoginConfig;\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictLoginConfig",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- }\r
- }\r
- }\r
- loginConfig = tempLoginConfig;\r
- }\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeResourceMap(fragment.getMessageDestinationRefs(), messageDestinationRefs,\r
- temp.getMessageDestinationRefs(), mergeInjectionFlags, fragment)) {\r
- return false;\r
- }\r
- }\r
- messageDestinationRefs.putAll(temp.getMessageDestinationRefs());\r
- mergeInjectionFlags.clear();\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeResourceMap(fragment.getMessageDestinations(), messageDestinations,\r
- temp.getMessageDestinations(), mergeInjectionFlags, fragment)) {\r
- return false;\r
- }\r
- }\r
- messageDestinations.putAll(temp.getMessageDestinations());\r
- mergeInjectionFlags.clear();\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeMap(fragment.getMimeMappings(), mimeMappings,\r
- temp.getMimeMappings(), fragment, "Mime Mapping")) {\r
- return false;\r
- }\r
- }\r
- mimeMappings.putAll(temp.getMimeMappings());\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeResourceMap(fragment.getResourceEnvRefs(), resourceEnvRefs,\r
- temp.getResourceEnvRefs(), mergeInjectionFlags, fragment)) {\r
- return false;\r
- }\r
- }\r
- resourceEnvRefs.putAll(temp.getResourceEnvRefs());\r
- mergeInjectionFlags.clear();\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeResourceMap(fragment.getResourceRefs(), resourceRefs,\r
- temp.getResourceRefs(), mergeInjectionFlags, fragment)) {\r
- return false;\r
- }\r
- }\r
- resourceRefs.putAll(temp.getResourceRefs());\r
- mergeInjectionFlags.clear();\r
-\r
- for (WebXml fragment : fragments) {\r
- for (SecurityConstraint constraint : fragment.getSecurityConstraints()) {\r
- // Always additive\r
- addSecurityConstraint(constraint);\r
- }\r
- }\r
-\r
- for (WebXml fragment : fragments) {\r
- for (String role : fragment.getSecurityRoles()) {\r
- // Always additive\r
- addSecurityRole(role);\r
- }\r
- }\r
-\r
- for (WebXml fragment : fragments) {\r
- if (!mergeResourceMap(fragment.getServiceRefs(), serviceRefs,\r
- temp.getServiceRefs(), mergeInjectionFlags, fragment)) {\r
- return false;\r
- }\r
- }\r
- serviceRefs.putAll(temp.getServiceRefs());\r
- mergeInjectionFlags.clear();\r
-\r
- // As per 'clarification' from the Servlet EG, servlet definitions and\r
- // mappings in the main web.xml override those in fragments and those in\r
- // fragments override those in annotations\r
- // Skip servlet definitions and mappings from fragments that are\r
- // defined in web.xml\r
- List<Map.Entry<String,String>> servletMappingsToAdd =\r
- new ArrayList<Map.Entry<String,String>>();\r
- for (WebXml fragment : fragments) {\r
- for (Map.Entry<String,String> servletMap :\r
- fragment.getServletMappings().entrySet()) {\r
- if (!servletMappingNames.contains(servletMap.getValue()) &&\r
- !servletMappings.containsKey(servletMap.getKey())) {\r
- servletMappingsToAdd.add(servletMap);\r
- }\r
- }\r
- }\r
- \r
- // Add fragment mappings\r
- for (Map.Entry<String,String> mapping : servletMappingsToAdd) {\r
- addServletMapping(mapping.getKey(), mapping.getValue());\r
- }\r
-\r
- for (WebXml fragment : fragments) {\r
- for (Map.Entry<String,ServletDef> entry :\r
- fragment.getServlets().entrySet()) {\r
- if (servlets.containsKey(entry.getKey())) {\r
- mergeServlet(entry.getValue(),\r
- servlets.get(entry.getKey()), false);\r
- } else {\r
- if (temp.getServlets().containsKey(entry.getKey())) {\r
- if (!(mergeServlet(entry.getValue(),\r
- temp.getServlets().get(entry.getKey()), true))) {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictServlet",\r
- entry.getKey(),\r
- fragment.getName(),\r
- fragment.getURL()));\r
- \r
- return false;\r
- }\r
- } else {\r
- temp.getServlets().put(entry.getKey(), entry.getValue());\r
- }\r
- }\r
- }\r
- }\r
- servlets.putAll(temp.getServlets());\r
- \r
- if (sessionConfig.getSessionTimeout() == null) {\r
- for (WebXml fragment : fragments) {\r
- Integer value = fragment.getSessionConfig().getSessionTimeout();\r
- if (value != null) {\r
- if (temp.getSessionConfig().getSessionTimeout() == null) {\r
- temp.getSessionConfig().setSessionTimeout(value.toString());\r
- } else if (value.equals(\r
- temp.getSessionConfig().getSessionTimeout())) {\r
- // Fragments use same value - no conflict\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictSessionTimeout",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- if (temp.getSessionConfig().getSessionTimeout() != null) {\r
- sessionConfig.setSessionTimeout(\r
- temp.getSessionConfig().getSessionTimeout().toString());\r
- }\r
- }\r
- \r
- if (sessionConfig.getCookieName() == null) {\r
- for (WebXml fragment : fragments) {\r
- String value = fragment.getSessionConfig().getCookieName();\r
- if (value != null) {\r
- if (temp.getSessionConfig().getCookieName() == null) {\r
- temp.getSessionConfig().setCookieName(value);\r
- } else if (value.equals(\r
- temp.getSessionConfig().getCookieName())) {\r
- // Fragments use same value - no conflict\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictSessionCookieName",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- sessionConfig.setCookieName(\r
- temp.getSessionConfig().getCookieName());\r
- }\r
- if (sessionConfig.getCookieDomain() == null) {\r
- for (WebXml fragment : fragments) {\r
- String value = fragment.getSessionConfig().getCookieDomain();\r
- if (value != null) {\r
- if (temp.getSessionConfig().getCookieDomain() == null) {\r
- temp.getSessionConfig().setCookieDomain(value);\r
- } else if (value.equals(\r
- temp.getSessionConfig().getCookieDomain())) {\r
- // Fragments use same value - no conflict\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictSessionCookieDomain",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- sessionConfig.setCookieDomain(\r
- temp.getSessionConfig().getCookieDomain());\r
- }\r
- if (sessionConfig.getCookiePath() == null) {\r
- for (WebXml fragment : fragments) {\r
- String value = fragment.getSessionConfig().getCookiePath();\r
- if (value != null) {\r
- if (temp.getSessionConfig().getCookiePath() == null) {\r
- temp.getSessionConfig().setCookiePath(value);\r
- } else if (value.equals(\r
- temp.getSessionConfig().getCookiePath())) {\r
- // Fragments use same value - no conflict\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictSessionCookiePath",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- sessionConfig.setCookiePath(\r
- temp.getSessionConfig().getCookiePath());\r
- }\r
- if (sessionConfig.getCookieComment() == null) {\r
- for (WebXml fragment : fragments) {\r
- String value = fragment.getSessionConfig().getCookieComment();\r
- if (value != null) {\r
- if (temp.getSessionConfig().getCookieComment() == null) {\r
- temp.getSessionConfig().setCookieComment(value);\r
- } else if (value.equals(\r
- temp.getSessionConfig().getCookieComment())) {\r
- // Fragments use same value - no conflict\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictSessionCookieComment",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- sessionConfig.setCookieComment(\r
- temp.getSessionConfig().getCookieComment());\r
- }\r
- if (sessionConfig.getCookieHttpOnly() == null) {\r
- for (WebXml fragment : fragments) {\r
- Boolean value = fragment.getSessionConfig().getCookieHttpOnly();\r
- if (value != null) {\r
- if (temp.getSessionConfig().getCookieHttpOnly() == null) {\r
- temp.getSessionConfig().setCookieHttpOnly(value.toString());\r
- } else if (value.equals(\r
- temp.getSessionConfig().getCookieHttpOnly())) {\r
- // Fragments use same value - no conflict\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictSessionCookieHttpOnly",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- if (temp.getSessionConfig().getCookieHttpOnly() != null) {\r
- sessionConfig.setCookieHttpOnly(\r
- temp.getSessionConfig().getCookieHttpOnly().toString());\r
- }\r
- }\r
- if (sessionConfig.getCookieSecure() == null) {\r
- for (WebXml fragment : fragments) {\r
- Boolean value = fragment.getSessionConfig().getCookieSecure();\r
- if (value != null) {\r
- if (temp.getSessionConfig().getCookieSecure() == null) {\r
- temp.getSessionConfig().setCookieSecure(value.toString());\r
- } else if (value.equals(\r
- temp.getSessionConfig().getCookieSecure())) {\r
- // Fragments use same value - no conflict\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictSessionCookieSecure",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- if (temp.getSessionConfig().getCookieSecure() != null) {\r
- sessionConfig.setCookieSecure(\r
- temp.getSessionConfig().getCookieSecure().toString());\r
- }\r
- }\r
- if (sessionConfig.getCookieMaxAge() == null) {\r
- for (WebXml fragment : fragments) {\r
- Integer value = fragment.getSessionConfig().getCookieMaxAge();\r
- if (value != null) {\r
- if (temp.getSessionConfig().getCookieMaxAge() == null) {\r
- temp.getSessionConfig().setCookieMaxAge(value.toString());\r
- } else if (value.equals(\r
- temp.getSessionConfig().getCookieMaxAge())) {\r
- // Fragments use same value - no conflict\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictSessionCookieMaxAge",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- if (temp.getSessionConfig().getCookieMaxAge() != null) {\r
- sessionConfig.setCookieMaxAge(\r
- temp.getSessionConfig().getCookieMaxAge().toString());\r
- }\r
- }\r
-\r
- if (sessionConfig.getSessionTrackingModes().size() == 0) {\r
- for (WebXml fragment : fragments) {\r
- EnumSet<SessionTrackingMode> value =\r
- fragment.getSessionConfig().getSessionTrackingModes();\r
- if (value.size() > 0) {\r
- if (temp.getSessionConfig().getSessionTrackingModes().size() == 0) {\r
- temp.getSessionConfig().getSessionTrackingModes().addAll(value);\r
- } else if (value.equals(\r
- temp.getSessionConfig().getSessionTrackingModes())) {\r
- // Fragments use same value - no conflict\r
- } else {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictSessionTrackingMode",\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- }\r
- }\r
- sessionConfig.getSessionTrackingModes().addAll(\r
- temp.getSessionConfig().getSessionTrackingModes());\r
- }\r
- \r
- for (WebXml fragment : fragments) {\r
- if (!mergeMap(fragment.getTaglibs(), taglibs,\r
- temp.getTaglibs(), fragment, "Taglibs")) {\r
- return false;\r
- }\r
- }\r
- taglibs.putAll(temp.getTaglibs());\r
-\r
- for (WebXml fragment : fragments) {\r
- if (fragment.alwaysAddWelcomeFiles || welcomeFiles.size() == 0) {\r
- for (String welcomeFile : fragment.getWelcomeFiles()) {\r
- addWelcomeFile(welcomeFile);\r
- }\r
- }\r
- }\r
-\r
- return true;\r
- }\r
- \r
- private static <T extends ResourceBase> boolean mergeResourceMap(\r
- Map<String, T> fragmentResources, Map<String, T> mainResources,\r
- Map<String, T> tempResources,\r
- Map<String,Boolean> mergeInjectionFlags, WebXml fragment) {\r
- for (T resource : fragmentResources.values()) {\r
- String resourceName = resource.getName();\r
- boolean mergeInjectionFlag = false;\r
- if (mainResources.containsKey(resourceName)) {\r
- if (mergeInjectionFlags.containsKey(resourceName)) {\r
- mergeInjectionFlag =\r
- mergeInjectionFlags.get(resourceName).booleanValue(); \r
- } else {\r
- if (mainResources.get(\r
- resourceName).getInjectionTargets().size() == 0) {\r
- mergeInjectionFlag = true;\r
- }\r
- mergeInjectionFlags.put(resourceName,\r
- Boolean.valueOf(mergeInjectionFlag));\r
- }\r
- if (mergeInjectionFlag) {\r
- mainResources.get(resourceName).getInjectionTargets().addAll(\r
- resource.getInjectionTargets());\r
- }\r
- } else {\r
- // Not defined in main web.xml\r
- if (tempResources.containsKey(resourceName)) {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictResource",\r
- resourceName,\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- } \r
- tempResources.put(resourceName, resource);\r
- }\r
- }\r
- return true;\r
- }\r
- \r
- private static <T> boolean mergeMap(Map<String,T> fragmentMap,\r
- Map<String,T> mainMap, Map<String,T> tempMap, WebXml fragment,\r
- String mapName) {\r
- for (Entry<String, T> entry : fragmentMap.entrySet()) {\r
- final String key = entry.getKey();\r
- if (!mainMap.containsKey(key)) {\r
- // Not defined in main web.xml\r
- T value = entry.getValue();\r
- if (tempMap.containsKey(key)) {\r
- if (value != null && !value.equals(\r
- tempMap.get(key))) {\r
- log.error(sm.getString(\r
- "webXml.mergeConflictString",\r
- mapName,\r
- key,\r
- fragment.getName(),\r
- fragment.getURL()));\r
- return false;\r
- }\r
- } else {\r
- tempMap.put(key, value);\r
- }\r
- }\r
- }\r
- return true;\r
- }\r
- \r
- private static boolean mergeFilter(FilterDef src, FilterDef dest,\r
- boolean failOnConflict) {\r
- if (dest.getAsyncSupported() == null) {\r
- dest.setAsyncSupported(src.getAsyncSupported());\r
- } else if (src.getAsyncSupported() != null) {\r
- if (failOnConflict &&\r
- !src.getAsyncSupported().equals(dest.getAsyncSupported())) {\r
- return false;\r
- }\r
- }\r
-\r
- if (dest.getFilterClass() == null) {\r
- dest.setFilterClass(src.getFilterClass());\r
- } else if (src.getFilterClass() != null) {\r
- if (failOnConflict &&\r
- !src.getFilterClass().equals(dest.getFilterClass())) {\r
- return false;\r
- }\r
- }\r
- \r
- for (Map.Entry<String,String> srcEntry :\r
- src.getParameterMap().entrySet()) {\r
- if (dest.getParameterMap().containsKey(srcEntry.getKey())) {\r
- if (failOnConflict && !dest.getParameterMap().get(\r
- srcEntry.getKey()).equals(srcEntry.getValue())) {\r
- return false;\r
- }\r
- } else {\r
- dest.addInitParameter(srcEntry.getKey(), srcEntry.getValue());\r
- }\r
- }\r
- return true;\r
- }\r
- \r
- private static boolean mergeServlet(ServletDef src, ServletDef dest,\r
- boolean failOnConflict) {\r
- // These tests should be unnecessary...\r
- if (dest.getServletClass() != null && dest.getJspFile() != null) {\r
- return false;\r
- }\r
- if (src.getServletClass() != null && src.getJspFile() != null) {\r
- return false;\r
- }\r
- \r
- \r
- if (dest.getServletClass() == null && dest.getJspFile() == null) {\r
- dest.setServletClass(src.getServletClass());\r
- dest.setJspFile(src.getJspFile());\r
- } else if (failOnConflict) {\r
- if (src.getServletClass() != null &&\r
- (dest.getJspFile() != null ||\r
- !src.getServletClass().equals(dest.getServletClass()))) {\r
- return false;\r
- }\r
- if (src.getJspFile() != null &&\r
- (dest.getServletClass() != null ||\r
- !src.getJspFile().equals(dest.getJspFile()))) {\r
- return false;\r
- }\r
- }\r
- \r
- // Additive\r
- for (SecurityRoleRef securityRoleRef : src.getSecurityRoleRefs()) {\r
- dest.addSecurityRoleRef(securityRoleRef);\r
- }\r
- \r
- if (dest.getLoadOnStartup() == null) {\r
- if (src.getLoadOnStartup() != null) {\r
- dest.setLoadOnStartup(src.getLoadOnStartup().toString());\r
- }\r
- } else if (src.getLoadOnStartup() != null) {\r
- if (failOnConflict &&\r
- !src.getLoadOnStartup().equals(dest.getLoadOnStartup())) {\r
- return false;\r
- }\r
- }\r
- \r
- if (dest.getEnabled() == null) {\r
- if (src.getEnabled() != null) {\r
- dest.setEnabled(src.getEnabled().toString());\r
- }\r
- } else if (src.getEnabled() != null) {\r
- if (failOnConflict &&\r
- !src.getEnabled().equals(dest.getEnabled())) {\r
- return false;\r
- }\r
- }\r
- \r
- for (Map.Entry<String,String> srcEntry :\r
- src.getParameterMap().entrySet()) {\r
- if (dest.getParameterMap().containsKey(srcEntry.getKey())) {\r
- if (failOnConflict && !dest.getParameterMap().get(\r
- srcEntry.getKey()).equals(srcEntry.getValue())) {\r
- return false;\r
- }\r
- } else {\r
- dest.addInitParameter(srcEntry.getKey(), srcEntry.getValue());\r
- }\r
- }\r
- \r
- if (dest.getMultipartDef() == null) {\r
- dest.setMultipartDef(src.getMultipartDef());\r
- } else if (src.getMultipartDef() != null) {\r
- return mergeMultipartDef(src.getMultipartDef(),\r
- dest.getMultipartDef(), failOnConflict);\r
- }\r
- \r
- if (dest.getAsyncSupported() == null) {\r
- if (src.getAsyncSupported() != null) {\r
- dest.setAsyncSupported(src.getAsyncSupported().toString());\r
- }\r
- } else if (src.getAsyncSupported() != null) {\r
- if (failOnConflict &&\r
- !src.getAsyncSupported().equals(dest.getAsyncSupported())) {\r
- return false;\r
- }\r
- }\r
- \r
- return true;\r
- }\r
-\r
- private static boolean mergeMultipartDef(MultipartDef src, MultipartDef dest,\r
- boolean failOnConflict) {\r
-\r
- if (dest.getLocation() == null) {\r
- dest.setLocation(src.getLocation());\r
- } else if (src.getLocation() != null) {\r
- if (failOnConflict &&\r
- !src.getLocation().equals(dest.getLocation())) {\r
- return false;\r
- }\r
- }\r
-\r
- if (dest.getFileSizeThreshold() == null) {\r
- dest.setFileSizeThreshold(src.getFileSizeThreshold());\r
- } else if (src.getFileSizeThreshold() != null) {\r
- if (failOnConflict &&\r
- !src.getFileSizeThreshold().equals(\r
- dest.getFileSizeThreshold())) {\r
- return false;\r
- }\r
- }\r
-\r
- if (dest.getMaxFileSize() == null) {\r
- dest.setMaxFileSize(src.getMaxFileSize());\r
- } else if (src.getLocation() != null) {\r
- if (failOnConflict &&\r
- !src.getMaxFileSize().equals(dest.getMaxFileSize())) {\r
- return false;\r
- }\r
- }\r
-\r
- if (dest.getMaxRequestSize() == null) {\r
- dest.setMaxRequestSize(src.getMaxRequestSize());\r
- } else if (src.getMaxRequestSize() != null) {\r
- if (failOnConflict &&\r
- !src.getMaxRequestSize().equals(\r
- dest.getMaxRequestSize())) {\r
- return false;\r
- }\r
- }\r
-\r
- return true;\r
- }\r
- \r
- \r
- /**\r
- * Generates the sub-set of the web-fragment.xml files to be processed in\r
- * the order that the fragments must be processed as per the rules in the\r
- * Servlet spec.\r
- * \r
- * @param application The application web.xml file\r
- * @param fragments The map of fragment names to web fragments\r
- * @return Ordered list of web-fragment.xml files to process\r
- */\r
- public static Set<WebXml> orderWebFragments(WebXml application,\r
- Map<String,WebXml> fragments) {\r
-\r
- Set<WebXml> orderedFragments = new LinkedHashSet<WebXml>();\r
- \r
- boolean absoluteOrdering =\r
- (application.getAbsoluteOrdering() != null);\r
- \r
- if (absoluteOrdering) {\r
- // Only those fragments listed should be processed\r
- Set<String> requestedOrder = application.getAbsoluteOrdering();\r
- \r
- for (String requestedName : requestedOrder) {\r
- if (WebXml.ORDER_OTHERS.equals(requestedName)) {\r
- // Add all fragments not named explicitly at this point\r
- for (Entry<String, WebXml> entry : fragments.entrySet()) {\r
- if (!requestedOrder.contains(entry.getKey())) {\r
- WebXml fragment = entry.getValue();\r
- if (fragment != null) {\r
- orderedFragments.add(fragment);\r
- }\r
- }\r
- }\r
- } else {\r
- WebXml fragment = fragments.get(requestedName);\r
- if (fragment != null) {\r
- orderedFragments.add(fragment);\r
- } else {\r
- log.warn(sm.getString("webXml.wrongFragmentName",requestedName));\r
- }\r
- }\r
- }\r
- } else {\r
- List<String> order = new LinkedList<String>();\r
- // Start by adding all fragments - order doesn't matter\r
- order.addAll(fragments.keySet());\r
- \r
- // Now go through and move elements to start/end depending on if\r
- // they specify others\r
- for (WebXml fragment : fragments.values()) {\r
- String name = fragment.getName();\r
- if (fragment.getBeforeOrdering().contains(WebXml.ORDER_OTHERS)) {\r
- // Move to beginning\r
- order.remove(name);\r
- order.add(0, name);\r
- } else if (fragment.getAfterOrdering().contains(WebXml.ORDER_OTHERS)) {\r
- // Move to end\r
- order.remove(name);\r
- order.add(name);\r
- }\r
- }\r
- \r
- // Now apply remaining ordering\r
- for (WebXml fragment : fragments.values()) {\r
- String name = fragment.getName();\r
- for (String before : fragment.getBeforeOrdering()) {\r
- if (!before.equals(WebXml.ORDER_OTHERS) &&\r
- order.contains(before) &&\r
- order.indexOf(before) < order.indexOf(name)) {\r
- order.remove(name);\r
- order.add(order.indexOf(before), name);\r
- }\r
- }\r
- for (String after : fragment.getAfterOrdering()) {\r
- if (!after.equals(WebXml.ORDER_OTHERS) &&\r
- order.contains(after) &&\r
- order.indexOf(after) > order.indexOf(name)) {\r
- order.remove(name);\r
- order.add(order.indexOf(after) + 1, name);\r
- }\r
- }\r
- }\r
- \r
- // Finally check ordering was applied correctly - if there are\r
- // errors then that indicates circular references\r
- for (WebXml fragment : fragments.values()) {\r
- String name = fragment.getName();\r
- for (String before : fragment.getBeforeOrdering()) {\r
- if (!before.equals(WebXml.ORDER_OTHERS) &&\r
- order.contains(before) &&\r
- order.indexOf(before) < order.indexOf(name)) {\r
- throw new IllegalArgumentException(sm.getString(""));\r
- }\r
- }\r
- for (String after : fragment.getAfterOrdering()) {\r
- if (!after.equals(WebXml.ORDER_OTHERS) &&\r
- order.contains(after) &&\r
- order.indexOf(after) > order.indexOf(name)) {\r
- throw new IllegalArgumentException();\r
- }\r
- }\r
- }\r
- \r
- // Build the ordered list\r
- for (String name : order) {\r
- orderedFragments.add(fragments.get(name));\r
- }\r
- }\r
- \r
- return orderedFragments;\r
- }\r
-\r
-} \r
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.catalina.deploy;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspPropertyGroupDescriptor;
+import javax.servlet.descriptor.TaglibDescriptor;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.core.ApplicationJspPropertyGroupDescriptor;
+import org.apache.catalina.core.ApplicationTaglibDescriptor;
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * Representation of common elements of web.xml and web-fragment.xml. Provides
+ * a repository for parsed data before the elements are merged.
+ * Validation is spread between multiple classes:
+ * The digester checks for structural correctness (eg single login-config)
+ * This class checks for invalid duplicates (eg filter/servlet names)
+ * StandardContext will check validity of values (eg URL formats etc)
+ */
+public class WebXml {
+
+ protected static final String ORDER_OTHERS =
+ "org.apache.catalina.order.others";
+
+ private static final StringManager sm =
+ StringManager.getManager(Constants.Package);
+
+ private static final org.apache.juli.logging.Log log=
+ org.apache.juli.logging.LogFactory.getLog(WebXml.class);
+
+ // Global defaults are overridable but Servlets and Servlet mappings need to
+ // be unique. Duplicates normally trigger an error. This flag indicates if
+ // newly added Servlet elements are marked as overridable.
+ private boolean overridable = false;
+ public boolean isOverridable() {
+ return overridable;
+ }
+ public void setOverridable(boolean overridable) {
+ this.overridable = overridable;
+ }
+
+ // web.xml only elements
+ // Absolute Ordering
+ private Set<String> absoluteOrdering = null;
+ public void addAbsoluteOrdering(String fragmentName) {
+ if (absoluteOrdering == null) {
+ absoluteOrdering = new LinkedHashSet<String>();
+ }
+ absoluteOrdering.add(fragmentName);
+ }
+ public void addAbsoluteOrderingOthers() {
+ if (absoluteOrdering == null) {
+ absoluteOrdering = new LinkedHashSet<String>();
+ }
+ absoluteOrdering.add(ORDER_OTHERS);
+ }
+ public Set<String> getAbsoluteOrdering() {
+ return absoluteOrdering;
+ }
+
+ // web-fragment.xml only elements
+ // Relative ordering
+ private Set<String> after = new LinkedHashSet<String>();
+ public void addAfterOrdering(String fragmentName) {
+ after.add(fragmentName);
+ }
+ public void addAfterOrderingOthers() {
+ if (before.contains(ORDER_OTHERS)) {
+ throw new IllegalArgumentException(sm.getString(
+ "webXml.multipleOther"));
+ }
+ after.add(ORDER_OTHERS);
+ }
+ public Set<String> getAfterOrdering() { return after; }
+
+ private Set<String> before = new LinkedHashSet<String>();
+ public void addBeforeOrdering(String fragmentName) {
+ before.add(fragmentName);
+ }
+ public void addBeforeOrderingOthers() {
+ if (after.contains(ORDER_OTHERS)) {
+ throw new IllegalArgumentException(sm.getString(
+ "webXml.multipleOther"));
+ }
+ before.add(ORDER_OTHERS);
+ }
+ public Set<String> getBeforeOrdering() { return before; }
+
+ // Common elements and attributes
+
+ // Required attribute of web-app element
+ public String getVersion() {
+ StringBuilder sb = new StringBuilder(3);
+ sb.append(majorVersion);
+ sb.append('.');
+ sb.append(minorVersion);
+ return sb.toString();
+ }
+ /**
+ * Set the version for this web.xml file
+ * @param version Values of <code>null</code> will be ignored
+ */
+ public void setVersion(String version) {
+ if (version == null) return;
+
+ // Update major and minor version
+ // Expected format is n.n - allow for any number of digits just in case
+ String major = null;
+ String minor = null;
+ int split = version.indexOf('.');
+ if (split < 0) {
+ // Major only
+ major = version;
+ } else {
+ major = version.substring(0, split);
+ minor = version.substring(split + 1);
+ }
+ if (major == null || major.length() == 0) {
+ majorVersion = 0;
+ } else {
+ try {
+ majorVersion = Integer.parseInt(major);
+ } catch (NumberFormatException nfe) {
+ log.warn(sm.getString("webXml.version.nfe", major, version),
+ nfe);
+ majorVersion = 0;
+ }
+ }
+
+ if (minor == null || minor.length() == 0) {
+ minorVersion = 0;
+ } else {
+ try {
+ minorVersion = Integer.parseInt(minor);
+ } catch (NumberFormatException nfe) {
+ log.warn(sm.getString("webXml.version.nfe", minor, version),
+ nfe);
+ minorVersion = 0;
+ }
+ }
+ }
+
+
+ // Optional publicId attribute
+ private String publicId = null;
+ public String getPublicId() { return publicId; }
+ public void setPublicId(String publicId) {
+ // Update major and minor version
+ if (publicId == null) {
+ // skip
+ } else if (org.apache.catalina.startup.Constants.WebSchemaPublicId_30.
+ equalsIgnoreCase(publicId) ||
+ org.apache.catalina.startup.Constants.WebFragmentSchemaPublicId_30.
+ equalsIgnoreCase(publicId)) {
+ majorVersion = 3;
+ minorVersion = 0;
+ this.publicId = publicId;
+ } else if (org.apache.catalina.startup.Constants.WebSchemaPublicId_25.
+ equalsIgnoreCase(publicId)) {
+ majorVersion = 2;
+ minorVersion = 5;
+ this.publicId = publicId;
+ } else if (org.apache.catalina.startup.Constants.WebSchemaPublicId_24.
+ equalsIgnoreCase(publicId)) {
+ majorVersion = 2;
+ minorVersion = 4;
+ this.publicId = publicId;
+ } else if (org.apache.catalina.startup.Constants.WebDtdPublicId_23.
+ equalsIgnoreCase(publicId)) {
+ majorVersion = 2;
+ minorVersion = 3;
+ this.publicId = publicId;
+ } else if (org.apache.catalina.startup.Constants.WebDtdPublicId_22.
+ equalsIgnoreCase(publicId)) {
+ majorVersion = 2;
+ minorVersion = 2;
+ this.publicId = publicId;
+ } else if ("datatypes".equals(publicId)) {
+ // Will occur when validation is enabled and dependencies are
+ // traced back. Ignore it.
+ } else {
+ // Unrecognised publicId
+ log.warn(sm.getString("webxml.unrecognisedPublicId", publicId));
+ }
+ }
+
+ // Optional metadata-complete attribute
+ private boolean metadataComplete = false;
+ public boolean isMetadataComplete() { return metadataComplete; }
+ public void setMetadataComplete(boolean metadataComplete) {
+ this.metadataComplete = metadataComplete; }
+
+ // Optional name element
+ private String name = null;
+ public String getName() { return name; }
+ public void setName(String name) {
+ if (ORDER_OTHERS.equalsIgnoreCase(name)) {
+ // This is unusual. This name will be ignored. Log the fact.
+ log.warn(sm.getString("webXml.reservedName", name));
+ } else {
+ this.name = name;
+ }
+ }
+
+ // Derived major and minor version attributes
+ // Default to 3.0 until we know otherwise
+ private int majorVersion = 3;
+ private int minorVersion = 0;
+ public int getMajorVersion() { return majorVersion; }
+ public int getMinorVersion() { return minorVersion; }
+
+ // web-app elements
+ // TODO: Ignored elements:
+ // - description
+ // - icon
+
+ // display-name - TODO should support multiple with language
+ private String displayName = null;
+ public String getDisplayName() { return displayName; }
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+
+ // distributable
+ private boolean distributable = false;
+ public boolean isDistributable() { return distributable; }
+ public void setDistributable(boolean distributable) {
+ this.distributable = distributable;
+ }
+
+ // context-param
+ // TODO: description (multiple with language) is ignored
+ private Map<String,String> contextParams = new HashMap<String,String>();
+ public void addContextParam(String param, String value) {
+ contextParams.put(param, value);
+ }
+ public Map<String,String> getContextParams() { return contextParams; }
+
+ // filter
+ // TODO: Should support multiple description elements with language
+ // TODO: Should support multiple display-name elements with language
+ // TODO: Should support multiple icon elements
+ // TODO: Description for init-param is ignored
+ private Map<String,FilterDef> filters =
+ new LinkedHashMap<String,FilterDef>();
+ public void addFilter(FilterDef filter) {
+ if (filters.containsKey(filter.getFilterName())) {
+ // Filter names must be unique within a web(-fragment).xml
+ throw new IllegalArgumentException(
+ sm.getString("webXml.duplicateFilter",
+ filter.getFilterName()));
+ }
+ filters.put(filter.getFilterName(), filter);
+ }
+ public Map<String,FilterDef> getFilters() { return filters; }
+
+ // filter-mapping
+ private Set<FilterMap> filterMaps = new LinkedHashSet<FilterMap>();
+ private Set<String> filterMappingNames = new HashSet<String>();
+ public void addFilterMapping(FilterMap filterMap) {
+ filterMaps.add(filterMap);
+ filterMappingNames.add(filterMap.getFilterName());
+ }
+ public Set<FilterMap> getFilterMappings() { return filterMaps; }
+
+ // listener
+ // TODO: description (multiple with language) is ignored
+ // TODO: display-name (multiple with language) is ignored
+ // TODO: icon (multiple) is ignored
+ private Set<String> listeners = new LinkedHashSet<String>();
+ public void addListener(String className) {
+ listeners.add(className);
+ }
+ public Set<String> getListeners() { return listeners; }
+
+ // servlet
+ // TODO: description (multiple with language) is ignored
+ // TODO: display-name (multiple with language) is ignored
+ // TODO: icon (multiple) is ignored
+ // TODO: init-param/description (multiple with language) is ignored
+ // TODO: security-role-ref/description (multiple with language) is ignored
+ private Map<String,ServletDef> servlets = new HashMap<String,ServletDef>();
+ public void addServlet(ServletDef servletDef) {
+ servlets.put(servletDef.getServletName(), servletDef);
+ if (overridable) {
+ servletDef.setOverridable(overridable);
+ }
+ }
+ public Map<String,ServletDef> getServlets() { return servlets; }
+
+ // servlet-mapping
+ private Map<String,String> servletMappings = new HashMap<String,String>();
+ private Set<String> servletMappingNames = new HashSet<String>();
+ public void addServletMapping(String urlPattern, String servletName) {
+ servletMappings.put(urlPattern, servletName);
+ servletMappingNames.add(servletName);
+ }
+ public Map<String,String> getServletMappings() { return servletMappings; }
+
+ // session-config
+ // Digester will check there is only one of these
+ private SessionConfig sessionConfig = new SessionConfig();
+ public void setSessionConfig(SessionConfig sessionConfig) {
+ this.sessionConfig = sessionConfig;
+ }
+ public SessionConfig getSessionConfig() { return sessionConfig; }
+
+ // mime-mapping
+ private Map<String,String> mimeMappings = new HashMap<String,String>();
+ public void addMimeMapping(String extension, String mimeType) {
+ mimeMappings.put(extension, mimeType);
+ }
+ public Map<String,String> getMimeMappings() { return mimeMappings; }
+
+ // welcome-file-list merge control
+ private boolean replaceWelcomeFiles = false;
+ private boolean alwaysAddWelcomeFiles = true;
+ /**
+ * When merging/parsing web.xml files into this web.xml should the current
+ * set be completely replaced?
+ */
+ public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) {
+ this.replaceWelcomeFiles = replaceWelcomeFiles;
+ }
+ /**
+ * When merging from this web.xml, should the welcome files be added to the
+ * target web.xml even if it already contains welcome file definitions.
+ */
+ public void setAlwaysAddWelcomeFiles(boolean alwaysAddWelcomeFiles) {
+ this.alwaysAddWelcomeFiles = alwaysAddWelcomeFiles;
+ }
+
+ // welcome-file-list
+ private Set<String> welcomeFiles = new LinkedHashSet<String>();
+ public void addWelcomeFile(String welcomeFile) {
+ if (replaceWelcomeFiles) {
+ welcomeFiles.clear();
+ replaceWelcomeFiles = false;
+ }
+ welcomeFiles.add(welcomeFile);
+ }
+ public Set<String> getWelcomeFiles() { return welcomeFiles; }
+
+ // error-page
+ private Map<String,ErrorPage> errorPages = new HashMap<String,ErrorPage>();
+ public void addErrorPage(ErrorPage errorPage) {
+ errorPages.put(errorPage.getName(), errorPage);
+ }
+ public Map<String,ErrorPage> getErrorPages() { return errorPages; }
+
+ // Digester will check there is only one jsp-config
+ // jsp-config/taglib or taglib (2.3 and earlier)
+ private Map<String,String> taglibs = new HashMap<String,String>();
+ public void addTaglib(String uri, String location) {
+ if (taglibs.containsKey(uri)) {
+ // Taglib URIs must be unique within a web(-fragment).xml
+ throw new IllegalArgumentException(
+ sm.getString("webXml.duplicateTaglibUri", uri));
+ }
+ taglibs.put(uri, location);
+ }
+ public Map<String,String> getTaglibs() { return taglibs; }
+
+ // jsp-config/jsp-property-group
+ private Set<JspPropertyGroup> jspPropertyGroups =
+ new HashSet<JspPropertyGroup>();
+ public void addJspPropertyGroup(JspPropertyGroup propertyGroup) {
+ jspPropertyGroups.add(propertyGroup);
+ }
+ public Set<JspPropertyGroup> getJspPropertyGroups() {
+ return jspPropertyGroups;
+ }
+
+ // security-constraint
+ // TODO: Should support multiple display-name elements with language
+ // TODO: Should support multiple description elements with language
+ private Set<SecurityConstraint> securityConstraints =
+ new HashSet<SecurityConstraint>();
+ public void addSecurityConstraint(SecurityConstraint securityConstraint) {
+ securityConstraints.add(securityConstraint);
+ }
+ public Set<SecurityConstraint> getSecurityConstraints() {
+ return securityConstraints;
+ }
+
+ // login-config
+ // Digester will check there is only one of these
+ private LoginConfig loginConfig = null;
+ public void setLoginConfig(LoginConfig loginConfig) {
+ this.loginConfig = loginConfig;
+ }
+ public LoginConfig getLoginConfig() { return loginConfig; }
+
+ // security-role
+ // TODO: description (multiple with language) is ignored
+ private Set<String> securityRoles = new HashSet<String>();
+ public void addSecurityRole(String securityRole) {
+ securityRoles.add(securityRole);
+ }
+ public Set<String> getSecurityRoles() { return securityRoles; }
+
+ // env-entry
+ // TODO: Should support multiple description elements with language
+ private Map<String,ContextEnvironment> envEntries =
+ new HashMap<String,ContextEnvironment>();
+ public void addEnvEntry(ContextEnvironment envEntry) {
+ if (envEntries.containsKey(envEntry.getName())) {
+ // env-entry names must be unique within a web(-fragment).xml
+ throw new IllegalArgumentException(
+ sm.getString("webXml.duplicateEnvEntry",
+ envEntry.getName()));
+ }
+ envEntries.put(envEntry.getName(),envEntry);
+ }
+ public Map<String,ContextEnvironment> getEnvEntries() { return envEntries; }
+
+ // ejb-ref
+ // TODO: Should support multiple description elements with language
+ private Map<String,ContextEjb> ejbRefs = new HashMap<String,ContextEjb>();
+ public void addEjbRef(ContextEjb ejbRef) {
+ ejbRefs.put(ejbRef.getName(),ejbRef);
+ }
+ public Map<String,ContextEjb> getEjbRefs() { return ejbRefs; }
+
+ // ejb-local-ref
+ // TODO: Should support multiple description elements with language
+ private Map<String,ContextLocalEjb> ejbLocalRefs =
+ new HashMap<String,ContextLocalEjb>();
+ public void addEjbLocalRef(ContextLocalEjb ejbLocalRef) {
+ ejbLocalRefs.put(ejbLocalRef.getName(),ejbLocalRef);
+ }
+ public Map<String,ContextLocalEjb> getEjbLocalRefs() {
+ return ejbLocalRefs;
+ }
+
+ // service-ref
+ // TODO: Should support multiple description elements with language
+ // TODO: Should support multiple display-names elements with language
+ // TODO: Should support multiple icon elements ???
+ private Map<String,ContextService> serviceRefs =
+ new HashMap<String,ContextService>();
+ public void addServiceRef(ContextService serviceRef) {
+ serviceRefs.put(serviceRef.getName(), serviceRef);
+ }
+ public Map<String,ContextService> getServiceRefs() { return serviceRefs; }
+
+ // resource-ref
+ // TODO: Should support multiple description elements with language
+ private Map<String,ContextResource> resourceRefs =
+ new HashMap<String,ContextResource>();
+ public void addResourceRef(ContextResource resourceRef) {
+ if (resourceRefs.containsKey(resourceRef.getName())) {
+ // resource-ref names must be unique within a web(-fragment).xml
+ throw new IllegalArgumentException(
+ sm.getString("webXml.duplicateResourceRef",
+ resourceRef.getName()));
+ }
+ resourceRefs.put(resourceRef.getName(), resourceRef);
+ }
+ public Map<String,ContextResource> getResourceRefs() {
+ return resourceRefs;
+ }
+
+ // resource-env-ref
+ // TODO: Should support multiple description elements with language
+ private Map<String,ContextResourceEnvRef> resourceEnvRefs =
+ new HashMap<String,ContextResourceEnvRef>();
+ public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) {
+ if (resourceEnvRefs.containsKey(resourceEnvRef.getName())) {
+ // resource-env-ref names must be unique within a web(-fragment).xml
+ throw new IllegalArgumentException(
+ sm.getString("webXml.duplicateResourceEnvRef",
+ resourceEnvRef.getName()));
+ }
+ resourceEnvRefs.put(resourceEnvRef.getName(), resourceEnvRef);
+ }
+ public Map<String,ContextResourceEnvRef> getResourceEnvRefs() {
+ return resourceEnvRefs;
+ }
+
+ // message-destination-ref
+ // TODO: Should support multiple description elements with language
+ private Map<String,MessageDestinationRef> messageDestinationRefs =
+ new HashMap<String,MessageDestinationRef>();
+ public void addMessageDestinationRef(
+ MessageDestinationRef messageDestinationRef) {
+ if (messageDestinationRefs.containsKey(
+ messageDestinationRef.getName())) {
+ // message-destination-ref names must be unique within a
+ // web(-fragment).xml
+ throw new IllegalArgumentException(sm.getString(
+ "webXml.duplicateMessageDestinationRef",
+ messageDestinationRef.getName()));
+ }
+ messageDestinationRefs.put(messageDestinationRef.getName(),
+ messageDestinationRef);
+ }
+ public Map<String,MessageDestinationRef> getMessageDestinationRefs() {
+ return messageDestinationRefs;
+ }
+
+ // message-destination
+ // TODO: Should support multiple description elements with language
+ // TODO: Should support multiple display-names elements with language
+ // TODO: Should support multiple icon elements ???
+ private Map<String,MessageDestination> messageDestinations =
+ new HashMap<String,MessageDestination>();
+ public void addMessageDestination(
+ MessageDestination messageDestination) {
+ if (messageDestinations.containsKey(
+ messageDestination.getName())) {
+ // message-destination names must be unique within a
+ // web(-fragment).xml
+ throw new IllegalArgumentException(
+ sm.getString("webXml.duplicateMessageDestination",
+ messageDestination.getName()));
+ }
+ messageDestinations.put(messageDestination.getName(),
+ messageDestination);
+ }
+ public Map<String,MessageDestination> getMessageDestinations() {
+ return messageDestinations;
+ }
+
+ // locale-encoging-mapping-list
+ private Map<String,String> localeEncodingMappings =
+ new HashMap<String,String>();
+ public void addLocaleEncodingMapping(String locale, String encoding) {
+ localeEncodingMappings.put(locale, encoding);
+ }
+ public Map<String,String> getLocalEncodingMappings() {
+ return localeEncodingMappings;
+ }
+
+
+ // Attributes not defined in web.xml or web-fragment.xml
+
+ // URL of JAR / exploded JAR for this web-fragment
+ private URL uRL = null;
+ public void setURL(URL url) { this.uRL = url; }
+ public URL getURL() { return uRL; }
+
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder(32);
+ buf.append("Name: ");
+ buf.append(getName());
+ buf.append(", URL: ");
+ buf.append(getURL());
+ return buf.toString();
+ }
+
+ private static final String INDENT2 = " ";
+ private static final String INDENT4 = " ";
+ private static final String INDENT6 = " ";
+
+ /**
+ * Generate a web.xml in String form that matches the representation stored
+ * in this object.
+ *
+ * @return The complete contents of web.xml as a String
+ */
+ public String toXml() {
+ StringBuilder sb = new StringBuilder(2048);
+
+ // TODO - Various, icon, description etc elements are skipped - mainly
+ // because they are ignored when web.xml is parsed - see above
+
+ // Declaration
+ sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+
+ // Root element
+ sb.append("<web-app xmlns=\"http://java.sun.com/xml/ns/javaee\"\n");
+ sb.append(" xmlns:xsi=");
+ sb.append("\"http://www.w3.org/2001/XMLSchema-instance\"\n");
+ sb.append(" xsi:schemaLocation=");
+ sb.append("\"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\"\n");
+ sb.append(" version=\"");
+ sb.append(getVersion());
+ sb.append("\"\n");
+ sb.append(" metadata-complete=\"true\">\n\n");
+
+ appendElement(sb, INDENT2, "display-name", displayName);
+
+ if (isDistributable()) {
+ sb.append(" <distributable/>\n\n");
+ }
+
+ for (Map.Entry<String, String> entry : contextParams.entrySet()) {
+ sb.append(" <context-param>\n");
+ appendElement(sb, INDENT4, "param-name", entry.getKey());
+ appendElement(sb, INDENT4, "param-valuee", entry.getValue());
+ sb.append(" </context-param>\n");
+ }
+ sb.append('\n');
+
+ for (Map.Entry<String, FilterDef> entry : filters.entrySet()) {
+ FilterDef filterDef = entry.getValue();
+ sb.append(" <filter>\n");
+ appendElement(sb, INDENT4, "description",
+ filterDef.getDescription());
+ appendElement(sb, INDENT4, "display-name",
+ filterDef.getDisplayName());
+ appendElement(sb, INDENT4, "filter-name",
+ filterDef.getFilterName());
+ appendElement(sb, INDENT4, "filter-class",
+ filterDef.getFilterClass());
+ appendElement(sb, INDENT4, "async-supported",
+ filterDef.getAsyncSupported());
+ for (Map.Entry<String, String> param :
+ filterDef.getParameterMap().entrySet()) {
+ sb.append(" <init-param>\n");
+ appendElement(sb, INDENT6, "param-name", param.getKey());
+ appendElement(sb, INDENT6, "param-value", param.getValue());
+ sb.append(" </init-param>\n");
+ }
+ sb.append(" </filter>\n");
+ }
+ sb.append('\n');
+
+ for (FilterMap filterMap : filterMaps) {
+ sb.append(" <filter-mapping>\n");
+ appendElement(sb, INDENT4, "filter-name",
+ filterMap.getFilterName());
+ if (filterMap.getMatchAllServletNames()) {
+ sb.append(" <servlet-name>*</servlet-name>\n");
+ } else {
+ for (String servletName : filterMap.getServletNames()) {
+ appendElement(sb, INDENT4, "servlet-name", servletName);
+ }
+ }
+ if (filterMap.getMatchAllUrlPatterns()) {
+ sb.append(" <url-pattern>*</url-pattern>\n");
+ } else {
+ for (String urlPattern : filterMap.getURLPatterns()) {
+ appendElement(sb, INDENT4, "url-pattern", urlPattern);
+ }
+ }
+ for (String dispatcher : filterMap.getDispatcherNames()) {
+ appendElement(sb, INDENT4, "dispatcher", dispatcher);
+ }
+ sb.append(" </filter-mapping>\n");
+ }
+ sb.append('\n');
+
+ for (String listener : listeners) {
+ sb.append(" <listener>\n");
+ appendElement(sb, INDENT4, "listener-class", listener);
+ sb.append(" </listener>\n");
+ }
+ sb.append('\n');
+
+ for (Map.Entry<String, ServletDef> entry : servlets.entrySet()) {
+ ServletDef servletDef = entry.getValue();
+ sb.append(" <servlet>\n");
+ appendElement(sb, INDENT4, "description",
+ servletDef.getDescription());
+ appendElement(sb, INDENT4, "display-name",
+ servletDef.getDisplayName());
+ appendElement(sb, INDENT4, "servlet-name", entry.getKey());
+ appendElement(sb, INDENT4, "servlet-class",
+ servletDef.getServletClass());
+ appendElement(sb, INDENT4, "jsp-file", servletDef.getJspFile());
+ for (Map.Entry<String, String> param :
+ servletDef.getParameterMap().entrySet()) {
+ sb.append(" <init-param>\n");
+ appendElement(sb, INDENT6, "param-name", param.getKey());
+ appendElement(sb, INDENT6, "param-value", param.getValue());
+ sb.append(" </init-param>\n");
+ }
+ appendElement(sb, INDENT4, "load-on-startup",
+ servletDef.getLoadOnStartup());
+ appendElement(sb, INDENT4, "enabled", servletDef.getEnabled());
+ appendElement(sb, INDENT4, "async-supported",
+ servletDef.getAsyncSupported());
+ if (servletDef.getRunAs() != null) {
+ sb.append(" <run-as>\n");
+ appendElement(sb, INDENT6, "role-name", servletDef.getRunAs());
+ sb.append(" </run-as>\n");
+ }
+ for (SecurityRoleRef roleRef : servletDef.getSecurityRoleRefs()) {
+ sb.append(" <security-role-ref>\n");
+ appendElement(sb, INDENT6, "role-name", roleRef.getName());
+ appendElement(sb, INDENT6, "role-link", roleRef.getLink());
+ sb.append(" </security-role-ref>\n");
+ }
+ MultipartDef multipartDef = servletDef.getMultipartDef();
+ if (multipartDef != null) {
+ sb.append(" <multipart-config>\n");
+ appendElement(sb, INDENT6, "location",
+ multipartDef.getLocation());
+ appendElement(sb, INDENT6, "max-file-size",
+ multipartDef.getMaxFileSize());
+ appendElement(sb, INDENT6, "max-request-size",
+ multipartDef.getMaxRequestSize());
+ appendElement(sb, INDENT6, "file-size-threshold",
+ multipartDef.getFileSizeThreshold());
+ sb.append(" </multipart-config>\n");
+ }
+ sb.append(" </servlet>\n");
+ }
+ sb.append('\n');
+
+ for (Map.Entry<String, String> entry : servletMappings.entrySet()) {
+ sb.append(" <servlet-mapping>\n");
+ appendElement(sb, INDENT4, "servlet-name", entry.getValue());
+ appendElement(sb, INDENT4, "url-pattern", entry.getKey());
+ sb.append(" </servlet-mapping>\n");
+ }
+ sb.append('\n');
+
+ if (sessionConfig != null) {
+ sb.append(" <session-config>\n");
+ appendElement(sb, INDENT4, "session-timeout",
+ sessionConfig.getSessionTimeout());
+ sb.append(" <cookie-config>\n");
+ appendElement(sb, INDENT6, "name", sessionConfig.getCookieName());
+ appendElement(sb, INDENT6, "domain",
+ sessionConfig.getCookieDomain());
+ appendElement(sb, INDENT6, "path", sessionConfig.getCookiePath());
+ appendElement(sb, INDENT6, "comment",
+ sessionConfig.getCookieComment());
+ appendElement(sb, INDENT6, "http-only",
+ sessionConfig.getCookieHttpOnly());
+ appendElement(sb, INDENT6, "secure",
+ sessionConfig.getCookieSecure());
+ appendElement(sb, INDENT6, "max-age",
+ sessionConfig.getCookieMaxAge());
+ sb.append(" </cookie-config>\n");
+ for (SessionTrackingMode stm :
+ sessionConfig.getSessionTrackingModes()) {
+ appendElement(sb, INDENT4, "tracking-mode", stm.name());
+ }
+ sb.append(" </session-config>\n\n");
+ }
+
+ for (Map.Entry<String, String> entry : mimeMappings.entrySet()) {
+ sb.append(" <mime-mapping>\n");
+ appendElement(sb, INDENT4, "extension", entry.getKey());
+ appendElement(sb, INDENT4, "mime-type", entry.getValue());
+ sb.append(" </mime-mapping>\n");
+ }
+ sb.append('\n');
+
+ if (welcomeFiles.size() > 0) {
+ sb.append(" <welcome-file-list>\n");
+ for (String welcomeFile : welcomeFiles) {
+ appendElement(sb, INDENT4, "welcome-file", welcomeFile);
+ }
+ sb.append(" </welcome-file-list>\n\n");
+ }
+
+ for (ErrorPage errorPage : errorPages.values()) {
+ sb.append(" <error-page>\n");
+ if (errorPage.getExceptionType() == null) {
+ appendElement(sb, INDENT4, "error-code",
+ Integer.toString(errorPage.getErrorCode()));
+ } else {
+ appendElement(sb, INDENT4, "exception-type",
+ errorPage.getExceptionType());
+ }
+ appendElement(sb, INDENT4, "location", errorPage.getLocation());
+ sb.append(" </error-page>\n");
+ }
+ sb.append('\n');
+
+ if (taglibs.size() > 0 || jspPropertyGroups.size() > 0) {
+ sb.append(" <jsp-config>\n");
+ for (Map.Entry<String, String> entry : taglibs.entrySet()) {
+ sb.append(" <taglib>\n");
+ appendElement(sb, INDENT6, "taglib-uri", entry.getKey());
+ appendElement(sb, INDENT6, "taglib-location", entry.getValue());
+ sb.append(" </taglib>\n");
+ }
+ for (JspPropertyGroup jpg : jspPropertyGroups) {
+ sb.append(" <jsp-property-group>\n");
+ appendElement(sb, INDENT6, "url-pattern", jpg.getUrlPattern());
+ appendElement(sb, INDENT6, "el-ignored", jpg.getElIgnored());
+ appendElement(sb, INDENT6, "scripting-invalid",
+ jpg.getScriptingInvalid());
+ appendElement(sb, INDENT6, "page-encoding",
+ jpg.getPageEncoding());
+ for (String prelude : jpg.getIncludePreludes()) {
+ appendElement(sb, INDENT6, "include-prelude", prelude);
+ }
+ for (String coda : jpg.getIncludeCodas()) {
+ appendElement(sb, INDENT6, "include-coda", coda);
+ }
+ appendElement(sb, INDENT6, "is-xml", jpg.getIsXml());
+ appendElement(sb, INDENT6, "deferred-syntax-allowed-as-literal",
+ jpg.getDeferredSyntax());
+ appendElement(sb, INDENT6, "trim-directive-whitespaces",
+ jpg.getTrimWhitespace());
+ appendElement(sb, INDENT6, "default-content-type",
+ jpg.getDefaultContentType());
+ appendElement(sb, INDENT6, "buffer", jpg.getBuffer());
+ appendElement(sb, INDENT6, "error-on-undeclared-namespace",
+ jpg.getErrorOnUndeclaredNamespace());
+ sb.append(" </jsp-property-group>\n");
+ }
+ sb.append(" </jsp-config>\n\n");
+ }
+
+ for (SecurityConstraint constraint : securityConstraints) {
+ sb.append(" <security-constraint>\n");
+ appendElement(sb, INDENT4, "display-name",
+ constraint.getDisplayName());
+ for (SecurityCollection collection : constraint.findCollections()) {
+ sb.append(" <web-resource-collection>\n");
+ appendElement(sb, INDENT6, "web-resource-name",
+ collection.getName());
+ appendElement(sb, INDENT6, "description",
+ collection.getDescription());
+ for (String urlPattern : collection.findPatterns()) {
+ appendElement(sb, INDENT6, "url-pattern", urlPattern);
+ }
+ for (String method : collection.findMethods()) {
+ appendElement(sb, INDENT6, "http-method", method);
+ }
+ for (String method : collection.findOmittedMethods()) {
+ appendElement(sb, INDENT6, "http-method-omission", method);
+ }
+ sb.append(" </web-resource-collection>\n");
+ }
+ if (constraint.findAuthRoles().length > 0) {
+ sb.append(" <auth-constraint>\n");
+ for (String role : constraint.findAuthRoles()) {
+ appendElement(sb, INDENT6, "role-name", role);
+ }
+ sb.append(" </auth-constraint>\n");
+ }
+ if (constraint.getUserConstraint() != null) {
+ sb.append(" <user-data-constraint>\n");
+ appendElement(sb, INDENT6, "transport-guarantee",
+ constraint.getUserConstraint());
+ sb.append(" </user-data-constraint>\n");
+ }
+ sb.append(" </security-constraint>\n");
+ }
+ sb.append('\n');
+
+ if (loginConfig != null) {
+ sb.append(" <login-config>\n");
+ appendElement(sb, INDENT4, "auth-method",
+ loginConfig.getAuthMethod());
+ appendElement(sb,INDENT4, "realm-name",
+ loginConfig.getRealmName());
+ if (loginConfig.getErrorPage() != null ||
+ loginConfig.getLoginPage() != null) {
+ sb.append(" <form-login-config>\n");
+ appendElement(sb, INDENT6, "form-login-page",
+ loginConfig.getLoginPage());
+ appendElement(sb, INDENT6, "form-error-page",
+ loginConfig.getErrorPage());
+ sb.append(" </form-login-config>\n");
+ }
+ sb.append(" </login-config>\n\n");
+ }
+
+ for (String roleName : securityRoles) {
+ sb.append(" <security-role>\n");
+ appendElement(sb, INDENT4, "role-name", roleName);
+ sb.append(" </security-role>\n");
+ }
+
+ for (ContextEnvironment envEntry : envEntries.values()) {
+ sb.append(" <env-entry>\n");
+ appendElement(sb, INDENT4, "description",
+ envEntry.getDescription());
+ appendElement(sb, INDENT4, "env-entry-name", envEntry.getName());
+ appendElement(sb, INDENT4, "env-entry-type", envEntry.getType());
+ appendElement(sb, INDENT4, "env-entry-value", envEntry.getValue());
+ // TODO mapped-name
+ for (InjectionTarget target : envEntry.getInjectionTargets()) {
+ sb.append(" <injection-target>\n");
+ appendElement(sb, INDENT6, "injection-target-class",
+ target.getTargetClass());
+ appendElement(sb, INDENT6, "injection-target-name",
+ target.getTargetName());
+ sb.append(" </injection-target>\n");
+ }
+ // TODO lookup-name
+ sb.append(" </env-entry>\n");
+ }
+ sb.append('\n');
+
+ for (ContextEjb ejbRef : ejbRefs.values()) {
+ sb.append(" <ejb-ref>\n");
+ appendElement(sb, INDENT4, "description", ejbRef.getDescription());
+ appendElement(sb, INDENT4, "ejb-ref-name", ejbRef.getName());
+ appendElement(sb, INDENT4, "ejb-ref-type", ejbRef.getType());
+ appendElement(sb, INDENT4, "home", ejbRef.getHome());
+ appendElement(sb, INDENT4, "remote", ejbRef.getRemote());
+ appendElement(sb, INDENT4, "ejb-link", ejbRef.getLink());
+ // TODO mapped-name
+ for (InjectionTarget target : ejbRef.getInjectionTargets()) {
+ sb.append(" <injection-target>\n");
+ appendElement(sb, INDENT6, "injection-target-class",
+ target.getTargetClass());
+ appendElement(sb, INDENT6, "injection-target-name",
+ target.getTargetName());
+ sb.append(" </injection-target>\n");
+ }
+ // TODO lookup-name
+ sb.append(" </ejb-ref>\n");
+ }
+ sb.append('\n');
+
+ for (ContextLocalEjb ejbLocalRef : ejbLocalRefs.values()) {
+ sb.append(" <ejb-local-ref>\n");
+ appendElement(sb, INDENT4, "description",
+ ejbLocalRef.getDescription());
+ appendElement(sb, INDENT4, "ejb-ref-name", ejbLocalRef.getName());
+ appendElement(sb, INDENT4, "ejb-ref-type", ejbLocalRef.getType());
+ appendElement(sb, INDENT4, "local-home", ejbLocalRef.getHome());
+ appendElement(sb, INDENT4, "local", ejbLocalRef.getLocal());
+ appendElement(sb, INDENT4, "ejb-link", ejbLocalRef.getLink());
+ // TODO mapped-name
+ for (InjectionTarget target : ejbLocalRef.getInjectionTargets()) {
+ sb.append(" <injection-target>\n");
+ appendElement(sb, INDENT6, "injection-target-class",
+ target.getTargetClass());
+ appendElement(sb, INDENT6, "injection-target-name",
+ target.getTargetName());
+ sb.append(" </injection-target>\n");
+ }
+ // TODO lookup-name
+ sb.append(" </ejb-local-ref>\n");
+ }
+ sb.append('\n');
+
+ for (ContextService serviceRef : serviceRefs.values()) {
+ sb.append(" <service-ref>\n");
+ appendElement(sb, INDENT4, "description",
+ serviceRef.getDescription());
+ appendElement(sb, INDENT4, "display-name",
+ serviceRef.getDisplayname());
+ appendElement(sb, INDENT4, "service-ref-name",
+ serviceRef.getName());
+ appendElement(sb, INDENT4, "service-interface",
+ serviceRef.getInterface());
+ appendElement(sb, INDENT4, "service-ref-type",
+ serviceRef.getType());
+ appendElement(sb, INDENT4, "wsdl-file", serviceRef.getWsdlfile());
+ appendElement(sb, INDENT4, "jaxrpc-mapping-file",
+ serviceRef.getJaxrpcmappingfile());
+ String qname = serviceRef.getServiceqnameNamespaceURI();
+ if (qname != null) {
+ qname = qname + ":";
+ }
+ qname = qname + serviceRef.getServiceqnameLocalpart();
+ appendElement(sb, INDENT4, "service-qname", qname);
+ Iterator<String> endpointIter = serviceRef.getServiceendpoints();
+ while (endpointIter.hasNext()) {
+ String endpoint = endpointIter.next();
+ sb.append(" <port-component-ref>\n");
+ appendElement(sb, INDENT6, "service-endpoint-interface",
+ endpoint);
+ appendElement(sb, INDENT6, "port-component-link",
+ serviceRef.getProperty(endpoint));
+ sb.append(" </port-component-ref>\n");
+ }
+ Iterator<String> handlerIter = serviceRef.getHandlers();
+ while (handlerIter.hasNext()) {
+ String handler = handlerIter.next();
+ sb.append(" <handler>\n");
+ ContextHandler ch = serviceRef.getHandler(handler);
+ appendElement(sb, INDENT6, "handler-name", ch.getName());
+ appendElement(sb, INDENT6, "handler-class",
+ ch.getHandlerclass());
+ sb.append(" </handler>\n");
+ }
+ // TODO handler-chains
+ // TODO mapped-name
+ for (InjectionTarget target : serviceRef.getInjectionTargets()) {
+ sb.append(" <injection-target>\n");
+ appendElement(sb, INDENT6, "injection-target-class",
+ target.getTargetClass());
+ appendElement(sb, INDENT6, "injection-target-name",
+ target.getTargetName());
+ sb.append(" </injection-target>\n");
+ }
+ // TODO lookup-name
+ sb.append(" </service-ref>\n");
+ }
+ sb.append('\n');
+
+ for (ContextResource resourceRef : resourceRefs.values()) {
+ sb.append(" <resource-ref>\n");
+ appendElement(sb, INDENT4, "description",
+ resourceRef.getDescription());
+ appendElement(sb, INDENT4, "res-ref-name", resourceRef.getName());
+ appendElement(sb, INDENT4, "res-type", resourceRef.getType());
+ appendElement(sb, INDENT4, "res-auth", resourceRef.getAuth());
+ appendElement(sb, INDENT4, "res-sharing-scope",
+ resourceRef.getScope());
+ // TODO mapped-name
+ for (InjectionTarget target : resourceRef.getInjectionTargets()) {
+ sb.append(" <injection-target>\n");
+ appendElement(sb, INDENT6, "injection-target-class",
+ target.getTargetClass());
+ appendElement(sb, INDENT6, "injection-target-name",
+ target.getTargetName());
+ sb.append(" </injection-target>\n");
+ }
+ // TODO lookup-name
+ sb.append(" </resource-ref>\n");
+ }
+ sb.append('\n');
+
+ for (ContextResourceEnvRef resourceEnvRef : resourceEnvRefs.values()) {
+ sb.append(" <resource-env-ref>\n");
+ appendElement(sb, INDENT4, "description",
+ resourceEnvRef.getDescription());
+ appendElement(sb, INDENT4, "resource-env-ref-name",
+ resourceEnvRef.getName());
+ appendElement(sb, INDENT4, "resource-env-ref-type",
+ resourceEnvRef.getType());
+ // TODO mapped-name
+ for (InjectionTarget target :
+ resourceEnvRef.getInjectionTargets()) {
+ sb.append(" <injection-target>\n");
+ appendElement(sb, INDENT6, "injection-target-class",
+ target.getTargetClass());
+ appendElement(sb, INDENT6, "injection-target-name",
+ target.getTargetName());
+ sb.append(" </injection-target>\n");
+ }
+ // TODO lookup-name
+ sb.append(" </resource-env-ref>\n");
+ }
+ sb.append('\n');
+
+ for (MessageDestinationRef mdr : messageDestinationRefs.values()) {
+ sb.append(" <message-destination-ref>\n");
+ appendElement(sb, INDENT4, "description", mdr.getDescription());
+ appendElement(sb, INDENT4, "message-destination-ref-name",
+ mdr.getName());
+ appendElement(sb, INDENT4, "message-destination-type",
+ mdr.getType());
+ appendElement(sb, INDENT4, "message-destination-usage",
+ mdr.getUsage());
+ appendElement(sb, INDENT4, "message-destination-link",
+ mdr.getLink());
+ // TODO mapped-name
+ for (InjectionTarget target : mdr.getInjectionTargets()) {
+ sb.append(" <injection-target>\n");
+ appendElement(sb, INDENT6, "injection-target-class",
+ target.getTargetClass());
+ appendElement(sb, INDENT6, "injection-target-name",
+ target.getTargetName());
+ sb.append(" </injection-target>\n");
+ }
+ // TODO lookup-name
+ sb.append(" </message-destination-ref>\n");
+ }
+ sb.append('\n');
+
+ for (MessageDestination md : messageDestinations.values()) {
+ sb.append(" <message-destination>\n");
+ appendElement(sb, INDENT4, "description", md.getDescription());
+ appendElement(sb, INDENT4, "display-name", md.getDisplayName());
+ appendElement(sb, INDENT4, "message-destination-name",
+ md.getName());
+ // TODO mapped-name
+ sb.append(" </message-destination>\n");
+ }
+ sb.append('\n');
+
+ if (localeEncodingMappings.size() > 0) {
+ sb.append(" <locale-encoding-mapping-list>\n");
+ for (Map.Entry<String, String> entry :
+ localeEncodingMappings.entrySet()) {
+ sb.append(" <locale-encoding-mapping>\n");
+ appendElement(sb, INDENT6, "locale", entry.getKey());
+ appendElement(sb, INDENT6, "encoding", entry.getValue());
+ sb.append(" </locale-encoding-mapping>\n");
+ }
+ sb.append(" </locale-encoding-mapping-list>\n");
+ }
+ sb.append("</web-app>");
+ return sb.toString();
+ }
+
+ private static void appendElement(StringBuilder sb, String indent,
+ String elementName, String value) {
+ if (value == null || value.length() == 0) return;
+ sb.append(indent);
+ sb.append('<');
+ sb.append(elementName);
+ sb.append('>');
+ sb.append(escapeXml(value));
+ sb.append("</");
+ sb.append(elementName);
+ sb.append(">\n");
+ }
+
+ private static void appendElement(StringBuilder sb, String indent,
+ String elementName, Object value) {
+ if (value == null) return;
+ appendElement(sb, indent, elementName, value.toString());
+ }
+
+
+ /**
+ * Escape the 5 entities defined by XML.
+ */
+ private static String escapeXml(String s) {
+ if (s == null)
+ return null;
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == '<') {
+ sb.append("<");
+ } else if (c == '>') {
+ sb.append(">");
+ } else if (c == '\'') {
+ sb.append("'");
+ } else if (c == '&') {
+ sb.append("&");
+ } else if (c == '"') {
+ sb.append(""");
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Configure a {@link Context} using the stored web.xml representation.
+ *
+ * @param context The context to be configured
+ */
+ public void configureContext(Context context) {
+ // As far as possible, process in alphabetical order so it is easy to
+ // check everything is present
+ // Some validation depends on correct public ID
+ context.setPublicId(publicId);
+
+ // Everything else in order
+ context.setEffectiveMajorVersion(getMajorVersion());
+ context.setEffectiveMinorVersion(getMinorVersion());
+
+ for (Entry<String, String> entry : contextParams.entrySet()) {
+ context.addParameter(entry.getKey(), entry.getValue());
+ }
+ context.setDisplayName(displayName);
+ context.setDistributable(distributable);
+ for (ContextLocalEjb ejbLocalRef : ejbLocalRefs.values()) {
+ context.getNamingResources().addLocalEjb(ejbLocalRef);
+ }
+ for (ContextEjb ejbRef : ejbRefs.values()) {
+ context.getNamingResources().addEjb(ejbRef);
+ }
+ for (ContextEnvironment environment : envEntries.values()) {
+ context.getNamingResources().addEnvironment(environment);
+ }
+ for (ErrorPage errorPage : errorPages.values()) {
+ context.addErrorPage(errorPage);
+ }
+ for (FilterDef filter : filters.values()) {
+ if (filter.getAsyncSupported() == null) {
+ filter.setAsyncSupported("false");
+ }
+ context.addFilterDef(filter);
+ }
+ for (FilterMap filterMap : filterMaps) {
+ context.addFilterMap(filterMap);
+ }
+ for (JspPropertyGroup jspPropertyGroup : jspPropertyGroups) {
+ JspPropertyGroupDescriptor descriptor =
+ new ApplicationJspPropertyGroupDescriptor(jspPropertyGroup);
+ context.getJspConfigDescriptor().getJspPropertyGroups().add(
+ descriptor);
+ }
+ for (String listener : listeners) {
+ context.addApplicationListener(listener);
+ }
+ for (Entry<String, String> entry : localeEncodingMappings.entrySet()) {
+ context.addLocaleEncodingMappingParameter(entry.getKey(),
+ entry.getValue());
+ }
+ // Prevents IAE
+ if (loginConfig != null) {
+ context.setLoginConfig(loginConfig);
+ }
+ for (MessageDestinationRef mdr : messageDestinationRefs.values()) {
+ context.getNamingResources().addMessageDestinationRef(mdr);
+ }
+
+ // messageDestinations were ignored in Tomcat 6, so ignore here
+
+ context.setIgnoreAnnotations(metadataComplete);
+ for (Entry<String, String> entry : mimeMappings.entrySet()) {
+ context.addMimeMapping(entry.getKey(), entry.getValue());
+ }
+ // Name is just used for ordering
+ for (ContextResourceEnvRef resource : resourceEnvRefs.values()) {
+ context.getNamingResources().addResourceEnvRef(resource);
+ }
+ for (ContextResource resource : resourceRefs.values()) {
+ context.getNamingResources().addResource(resource);
+ }
+ for (SecurityConstraint constraint : securityConstraints) {
+ context.addConstraint(constraint);
+ }
+ for (String role : securityRoles) {
+ context.addSecurityRole(role);
+ }
+ for (ContextService service : serviceRefs.values()) {
+ context.getNamingResources().addService(service);
+ }
+ for (ServletDef servlet : servlets.values()) {
+ Wrapper wrapper = context.createWrapper();
+ // Description is ignored
+ // Display name is ignored
+ // Icons are ignored
+
+ // jsp-file gets passed to the JSP Servlet as an init-param
+
+ if (servlet.getLoadOnStartup() != null) {
+ wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());
+ }
+ if (servlet.getEnabled() != null) {
+ wrapper.setEnabled(servlet.getEnabled().booleanValue());
+ }
+ wrapper.setName(servlet.getServletName());
+ Map<String,String> params = servlet.getParameterMap();
+ for (Entry<String, String> entry : params.entrySet()) {
+ wrapper.addInitParameter(entry.getKey(), entry.getValue());
+ }
+ wrapper.setRunAs(servlet.getRunAs());
+ Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();
+ for (SecurityRoleRef roleRef : roleRefs) {
+ wrapper.addSecurityReference(
+ roleRef.getName(), roleRef.getLink());
+ }
+ wrapper.setServletClass(servlet.getServletClass());
+ MultipartDef multipartdef = servlet.getMultipartDef();
+ if (multipartdef != null) {
+ if (multipartdef.getMaxFileSize() != null &&
+ multipartdef.getMaxRequestSize()!= null &&
+ multipartdef.getFileSizeThreshold() != null) {
+ wrapper.setMultipartConfigElement(new MultipartConfigElement(
+ multipartdef.getLocation(),
+ Long.parseLong(multipartdef.getMaxFileSize()),
+ Long.parseLong(multipartdef.getMaxRequestSize()),
+ Integer.parseInt(
+ multipartdef.getFileSizeThreshold())));
+ } else {
+ wrapper.setMultipartConfigElement(new MultipartConfigElement(
+ multipartdef.getLocation()));
+ }
+ }
+ if (servlet.getAsyncSupported() != null) {
+ wrapper.setAsyncSupported(
+ servlet.getAsyncSupported().booleanValue());
+ }
+ wrapper.setOverridable(servlet.isOverridable());
+ context.addChild(wrapper);
+ }
+ for (Entry<String, String> entry : servletMappings.entrySet()) {
+ context.addServletMapping(entry.getKey(), entry.getValue());
+ }
+ if (sessionConfig != null) {
+ if (sessionConfig.getSessionTimeout() != null) {
+ context.setSessionTimeout(
+ sessionConfig.getSessionTimeout().intValue());
+ }
+ SessionCookieConfig scc =
+ context.getServletContext().getSessionCookieConfig();
+ scc.setName(sessionConfig.getCookieName());
+ scc.setDomain(sessionConfig.getCookieDomain());
+ scc.setPath(sessionConfig.getCookiePath());
+ scc.setComment(sessionConfig.getCookieComment());
+ if (sessionConfig.getCookieHttpOnly() != null) {
+ scc.setHttpOnly(sessionConfig.getCookieHttpOnly().booleanValue());
+ }
+ if (sessionConfig.getCookieSecure() != null) {
+ scc.setSecure(sessionConfig.getCookieSecure().booleanValue());
+ }
+ if (sessionConfig.getCookieMaxAge() != null) {
+ scc.setMaxAge(sessionConfig.getCookieMaxAge().intValue());
+ }
+ if (sessionConfig.getSessionTrackingModes().size() > 0) {
+ context.getServletContext().setSessionTrackingModes(
+ sessionConfig.getSessionTrackingModes());
+ }
+ }
+ for (Entry<String, String> entry : taglibs.entrySet()) {
+ TaglibDescriptor descriptor = new ApplicationTaglibDescriptor(
+ entry.getValue(), entry.getKey());
+ context.getJspConfigDescriptor().getTaglibs().add(descriptor);
+ }
+
+ // Context doesn't use version directly
+
+ for (String welcomeFile : welcomeFiles) {
+ /*
+ * The following will result in a welcome file of "" so don't add
+ * that to the context
+ * <welcome-file-list>
+ * <welcome-file/>
+ * </welcome-file-list>
+ */
+ if (welcomeFile != null && welcomeFile.length() > 0) {
+ context.addWelcomeFile(welcomeFile);
+ }
+ }
+
+ // Do this last as it depends on servlets
+ for (JspPropertyGroup jspPropertyGroup : jspPropertyGroups) {
+ String jspServletName = context.findServletMapping("*.jsp");
+ if (jspServletName == null) {
+ jspServletName = "jsp";
+ }
+ if (context.findChild(jspServletName) != null) {
+ context.addServletMapping(jspPropertyGroup.getUrlPattern(),
+ jspServletName, true);
+ } else {
+ if(log.isDebugEnabled())
+ log.debug("Skiping " + jspPropertyGroup.getUrlPattern() +
+ " , no servlet " + jspServletName);
+ }
+ }
+ }
+
+ /**
+ * Merge the supplied web fragments into this main web.xml.
+ *
+ * @param fragments The fragments to merge in
+ * @return <code>true</code> if merge is successful, else
+ * <code>false</code>
+ */
+ public boolean merge(Set<WebXml> fragments) {
+ // As far as possible, process in alphabetical order so it is easy to
+ // check everything is present
+
+ // Merge rules vary from element to element. See SRV.8.2.3
+
+ WebXml temp = new WebXml();
+ Map<String,Boolean> mergeInjectionFlags =
+ new HashMap<String, Boolean>();
+
+ for (WebXml fragment : fragments) {
+ if (!mergeMap(fragment.getContextParams(), contextParams,
+ temp.getContextParams(), fragment, "Context Parameter")) {
+ return false;
+ }
+ }
+ contextParams.putAll(temp.getContextParams());
+
+ if (displayName == null) {
+ for (WebXml fragment : fragments) {
+ String value = fragment.getDisplayName();
+ if (value != null) {
+ if (temp.getDisplayName() == null) {
+ temp.setDisplayName(value);
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictDisplayName",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ displayName = temp.getDisplayName();
+ }
+
+ if (distributable) {
+ for (WebXml fragment : fragments) {
+ if (!fragment.isDistributable()) {
+ distributable = false;
+ break;
+ }
+ }
+ }
+
+ for (WebXml fragment : fragments) {
+ if (!mergeResourceMap(fragment.getEjbLocalRefs(), ejbLocalRefs,
+ temp.getEjbLocalRefs(), mergeInjectionFlags, fragment)) {
+ return false;
+ }
+ }
+ ejbLocalRefs.putAll(temp.getEjbLocalRefs());
+ mergeInjectionFlags.clear();
+
+ for (WebXml fragment : fragments) {
+ if (!mergeResourceMap(fragment.getEjbRefs(), ejbRefs,
+ temp.getEjbRefs(), mergeInjectionFlags, fragment)) {
+ return false;
+ }
+ }
+ ejbRefs.putAll(temp.getEjbRefs());
+ mergeInjectionFlags.clear();
+
+ for (WebXml fragment : fragments) {
+ if (!mergeResourceMap(fragment.getEnvEntries(), envEntries,
+ temp.getEnvEntries(), mergeInjectionFlags, fragment)) {
+ return false;
+ }
+ }
+ envEntries.putAll(temp.getEnvEntries());
+ mergeInjectionFlags.clear();
+
+ for (WebXml fragment : fragments) {
+ if (!mergeMap(fragment.getErrorPages(), errorPages,
+ temp.getErrorPages(), fragment, "Error Page")) {
+ return false;
+ }
+ }
+ errorPages.putAll(temp.getErrorPages());
+
+ // As per 'clarification' from the Servlet EG, filter definitions in the
+ // main web.xml override those in fragments and those in fragments
+ // override those in annotations
+ List<FilterMap> filterMapsToAdd = new ArrayList<FilterMap>();
+ for (WebXml fragment : fragments) {
+ for (FilterMap filterMap : fragment.getFilterMappings()) {
+ if (!filterMappingNames.contains(filterMap.getFilterName())) {
+ filterMapsToAdd.add(filterMap);
+ }
+ }
+ }
+ for (FilterMap filterMap : filterMapsToAdd) {
+ // Additive
+ addFilterMapping(filterMap);
+ }
+
+ for (WebXml fragment : fragments) {
+ for (Map.Entry<String,FilterDef> entry :
+ fragment.getFilters().entrySet()) {
+ if (filters.containsKey(entry.getKey())) {
+ mergeFilter(entry.getValue(),
+ filters.get(entry.getKey()), false);
+ } else {
+ if (temp.getFilters().containsKey(entry.getKey())) {
+ if (!(mergeFilter(entry.getValue(),
+ temp.getFilters().get(entry.getKey()), true))) {
+ log.error(sm.getString(
+ "webXml.mergeConflictFilter",
+ entry.getKey(),
+ fragment.getName(),
+ fragment.getURL()));
+
+ return false;
+ }
+ } else {
+ temp.getFilters().put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ }
+ filters.putAll(temp.getFilters());
+
+ for (WebXml fragment : fragments) {
+ for (JspPropertyGroup jspPropertyGroup :
+ fragment.getJspPropertyGroups()) {
+ // Always additive
+ addJspPropertyGroup(jspPropertyGroup);
+ }
+ }
+
+ for (WebXml fragment : fragments) {
+ for (String listener : fragment.getListeners()) {
+ // Always additive
+ addListener(listener);
+ }
+ }
+
+ for (WebXml fragment : fragments) {
+ if (!mergeMap(fragment.getLocalEncodingMappings(),
+ localeEncodingMappings, temp.getLocalEncodingMappings(),
+ fragment, "Locale Encoding Mapping")) {
+ return false;
+ }
+ }
+ localeEncodingMappings.putAll(temp.getLocalEncodingMappings());
+
+ if (getLoginConfig() == null) {
+ LoginConfig tempLoginConfig = null;
+ for (WebXml fragment : fragments) {
+ LoginConfig fragmentLoginConfig = fragment.loginConfig;
+ if (fragmentLoginConfig != null) {
+ if (tempLoginConfig == null ||
+ fragmentLoginConfig.equals(tempLoginConfig)) {
+ tempLoginConfig = fragmentLoginConfig;
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictLoginConfig",
+ fragment.getName(),
+ fragment.getURL()));
+ }
+ }
+ }
+ loginConfig = tempLoginConfig;
+ }
+
+ for (WebXml fragment : fragments) {
+ if (!mergeResourceMap(fragment.getMessageDestinationRefs(), messageDestinationRefs,
+ temp.getMessageDestinationRefs(), mergeInjectionFlags, fragment)) {
+ return false;
+ }
+ }
+ messageDestinationRefs.putAll(temp.getMessageDestinationRefs());
+ mergeInjectionFlags.clear();
+
+ for (WebXml fragment : fragments) {
+ if (!mergeResourceMap(fragment.getMessageDestinations(), messageDestinations,
+ temp.getMessageDestinations(), mergeInjectionFlags, fragment)) {
+ return false;
+ }
+ }
+ messageDestinations.putAll(temp.getMessageDestinations());
+ mergeInjectionFlags.clear();
+
+ for (WebXml fragment : fragments) {
+ if (!mergeMap(fragment.getMimeMappings(), mimeMappings,
+ temp.getMimeMappings(), fragment, "Mime Mapping")) {
+ return false;
+ }
+ }
+ mimeMappings.putAll(temp.getMimeMappings());
+
+ for (WebXml fragment : fragments) {
+ if (!mergeResourceMap(fragment.getResourceEnvRefs(), resourceEnvRefs,
+ temp.getResourceEnvRefs(), mergeInjectionFlags, fragment)) {
+ return false;
+ }
+ }
+ resourceEnvRefs.putAll(temp.getResourceEnvRefs());
+ mergeInjectionFlags.clear();
+
+ for (WebXml fragment : fragments) {
+ if (!mergeResourceMap(fragment.getResourceRefs(), resourceRefs,
+ temp.getResourceRefs(), mergeInjectionFlags, fragment)) {
+ return false;
+ }
+ }
+ resourceRefs.putAll(temp.getResourceRefs());
+ mergeInjectionFlags.clear();
+
+ for (WebXml fragment : fragments) {
+ for (SecurityConstraint constraint : fragment.getSecurityConstraints()) {
+ // Always additive
+ addSecurityConstraint(constraint);
+ }
+ }
+
+ for (WebXml fragment : fragments) {
+ for (String role : fragment.getSecurityRoles()) {
+ // Always additive
+ addSecurityRole(role);
+ }
+ }
+
+ for (WebXml fragment : fragments) {
+ if (!mergeResourceMap(fragment.getServiceRefs(), serviceRefs,
+ temp.getServiceRefs(), mergeInjectionFlags, fragment)) {
+ return false;
+ }
+ }
+ serviceRefs.putAll(temp.getServiceRefs());
+ mergeInjectionFlags.clear();
+
+ // As per 'clarification' from the Servlet EG, servlet definitions and
+ // mappings in the main web.xml override those in fragments and those in
+ // fragments override those in annotations
+ // Skip servlet definitions and mappings from fragments that are
+ // defined in web.xml
+ List<Map.Entry<String,String>> servletMappingsToAdd =
+ new ArrayList<Map.Entry<String,String>>();
+ for (WebXml fragment : fragments) {
+ for (Map.Entry<String,String> servletMap :
+ fragment.getServletMappings().entrySet()) {
+ if (!servletMappingNames.contains(servletMap.getValue()) &&
+ !servletMappings.containsKey(servletMap.getKey())) {
+ servletMappingsToAdd.add(servletMap);
+ }
+ }
+ }
+
+ // Add fragment mappings
+ for (Map.Entry<String,String> mapping : servletMappingsToAdd) {
+ addServletMapping(mapping.getKey(), mapping.getValue());
+ }
+
+ for (WebXml fragment : fragments) {
+ for (Map.Entry<String,ServletDef> entry :
+ fragment.getServlets().entrySet()) {
+ if (servlets.containsKey(entry.getKey())) {
+ mergeServlet(entry.getValue(),
+ servlets.get(entry.getKey()), false);
+ } else {
+ if (temp.getServlets().containsKey(entry.getKey())) {
+ if (!(mergeServlet(entry.getValue(),
+ temp.getServlets().get(entry.getKey()), true))) {
+ log.error(sm.getString(
+ "webXml.mergeConflictServlet",
+ entry.getKey(),
+ fragment.getName(),
+ fragment.getURL()));
+
+ return false;
+ }
+ } else {
+ temp.getServlets().put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ }
+ servlets.putAll(temp.getServlets());
+
+ if (sessionConfig.getSessionTimeout() == null) {
+ for (WebXml fragment : fragments) {
+ Integer value = fragment.getSessionConfig().getSessionTimeout();
+ if (value != null) {
+ if (temp.getSessionConfig().getSessionTimeout() == null) {
+ temp.getSessionConfig().setSessionTimeout(value.toString());
+ } else if (value.equals(
+ temp.getSessionConfig().getSessionTimeout())) {
+ // Fragments use same value - no conflict
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictSessionTimeout",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ if (temp.getSessionConfig().getSessionTimeout() != null) {
+ sessionConfig.setSessionTimeout(
+ temp.getSessionConfig().getSessionTimeout().toString());
+ }
+ }
+
+ if (sessionConfig.getCookieName() == null) {
+ for (WebXml fragment : fragments) {
+ String value = fragment.getSessionConfig().getCookieName();
+ if (value != null) {
+ if (temp.getSessionConfig().getCookieName() == null) {
+ temp.getSessionConfig().setCookieName(value);
+ } else if (value.equals(
+ temp.getSessionConfig().getCookieName())) {
+ // Fragments use same value - no conflict
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictSessionCookieName",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ sessionConfig.setCookieName(
+ temp.getSessionConfig().getCookieName());
+ }
+ if (sessionConfig.getCookieDomain() == null) {
+ for (WebXml fragment : fragments) {
+ String value = fragment.getSessionConfig().getCookieDomain();
+ if (value != null) {
+ if (temp.getSessionConfig().getCookieDomain() == null) {
+ temp.getSessionConfig().setCookieDomain(value);
+ } else if (value.equals(
+ temp.getSessionConfig().getCookieDomain())) {
+ // Fragments use same value - no conflict
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictSessionCookieDomain",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ sessionConfig.setCookieDomain(
+ temp.getSessionConfig().getCookieDomain());
+ }
+ if (sessionConfig.getCookiePath() == null) {
+ for (WebXml fragment : fragments) {
+ String value = fragment.getSessionConfig().getCookiePath();
+ if (value != null) {
+ if (temp.getSessionConfig().getCookiePath() == null) {
+ temp.getSessionConfig().setCookiePath(value);
+ } else if (value.equals(
+ temp.getSessionConfig().getCookiePath())) {
+ // Fragments use same value - no conflict
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictSessionCookiePath",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ sessionConfig.setCookiePath(
+ temp.getSessionConfig().getCookiePath());
+ }
+ if (sessionConfig.getCookieComment() == null) {
+ for (WebXml fragment : fragments) {
+ String value = fragment.getSessionConfig().getCookieComment();
+ if (value != null) {
+ if (temp.getSessionConfig().getCookieComment() == null) {
+ temp.getSessionConfig().setCookieComment(value);
+ } else if (value.equals(
+ temp.getSessionConfig().getCookieComment())) {
+ // Fragments use same value - no conflict
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictSessionCookieComment",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ sessionConfig.setCookieComment(
+ temp.getSessionConfig().getCookieComment());
+ }
+ if (sessionConfig.getCookieHttpOnly() == null) {
+ for (WebXml fragment : fragments) {
+ Boolean value = fragment.getSessionConfig().getCookieHttpOnly();
+ if (value != null) {
+ if (temp.getSessionConfig().getCookieHttpOnly() == null) {
+ temp.getSessionConfig().setCookieHttpOnly(value.toString());
+ } else if (value.equals(
+ temp.getSessionConfig().getCookieHttpOnly())) {
+ // Fragments use same value - no conflict
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictSessionCookieHttpOnly",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ if (temp.getSessionConfig().getCookieHttpOnly() != null) {
+ sessionConfig.setCookieHttpOnly(
+ temp.getSessionConfig().getCookieHttpOnly().toString());
+ }
+ }
+ if (sessionConfig.getCookieSecure() == null) {
+ for (WebXml fragment : fragments) {
+ Boolean value = fragment.getSessionConfig().getCookieSecure();
+ if (value != null) {
+ if (temp.getSessionConfig().getCookieSecure() == null) {
+ temp.getSessionConfig().setCookieSecure(value.toString());
+ } else if (value.equals(
+ temp.getSessionConfig().getCookieSecure())) {
+ // Fragments use same value - no conflict
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictSessionCookieSecure",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ if (temp.getSessionConfig().getCookieSecure() != null) {
+ sessionConfig.setCookieSecure(
+ temp.getSessionConfig().getCookieSecure().toString());
+ }
+ }
+ if (sessionConfig.getCookieMaxAge() == null) {
+ for (WebXml fragment : fragments) {
+ Integer value = fragment.getSessionConfig().getCookieMaxAge();
+ if (value != null) {
+ if (temp.getSessionConfig().getCookieMaxAge() == null) {
+ temp.getSessionConfig().setCookieMaxAge(value.toString());
+ } else if (value.equals(
+ temp.getSessionConfig().getCookieMaxAge())) {
+ // Fragments use same value - no conflict
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictSessionCookieMaxAge",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ if (temp.getSessionConfig().getCookieMaxAge() != null) {
+ sessionConfig.setCookieMaxAge(
+ temp.getSessionConfig().getCookieMaxAge().toString());
+ }
+ }
+
+ if (sessionConfig.getSessionTrackingModes().size() == 0) {
+ for (WebXml fragment : fragments) {
+ EnumSet<SessionTrackingMode> value =
+ fragment.getSessionConfig().getSessionTrackingModes();
+ if (value.size() > 0) {
+ if (temp.getSessionConfig().getSessionTrackingModes().size() == 0) {
+ temp.getSessionConfig().getSessionTrackingModes().addAll(value);
+ } else if (value.equals(
+ temp.getSessionConfig().getSessionTrackingModes())) {
+ // Fragments use same value - no conflict
+ } else {
+ log.error(sm.getString(
+ "webXml.mergeConflictSessionTrackingMode",
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ }
+ }
+ sessionConfig.getSessionTrackingModes().addAll(
+ temp.getSessionConfig().getSessionTrackingModes());
+ }
+
+ for (WebXml fragment : fragments) {
+ if (!mergeMap(fragment.getTaglibs(), taglibs,
+ temp.getTaglibs(), fragment, "Taglibs")) {
+ return false;
+ }
+ }
+ taglibs.putAll(temp.getTaglibs());
+
+ for (WebXml fragment : fragments) {
+ if (fragment.alwaysAddWelcomeFiles || welcomeFiles.size() == 0) {
+ for (String welcomeFile : fragment.getWelcomeFiles()) {
+ addWelcomeFile(welcomeFile);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static <T extends ResourceBase> boolean mergeResourceMap(
+ Map<String, T> fragmentResources, Map<String, T> mainResources,
+ Map<String, T> tempResources,
+ Map<String,Boolean> mergeInjectionFlags, WebXml fragment) {
+ for (T resource : fragmentResources.values()) {
+ String resourceName = resource.getName();
+ boolean mergeInjectionFlag = false;
+ if (mainResources.containsKey(resourceName)) {
+ if (mergeInjectionFlags.containsKey(resourceName)) {
+ mergeInjectionFlag =
+ mergeInjectionFlags.get(resourceName).booleanValue();
+ } else {
+ if (mainResources.get(
+ resourceName).getInjectionTargets().size() == 0) {
+ mergeInjectionFlag = true;
+ }
+ mergeInjectionFlags.put(resourceName,
+ Boolean.valueOf(mergeInjectionFlag));
+ }
+ if (mergeInjectionFlag) {
+ mainResources.get(resourceName).getInjectionTargets().addAll(
+ resource.getInjectionTargets());
+ }
+ } else {
+ // Not defined in main web.xml
+ if (tempResources.containsKey(resourceName)) {
+ log.error(sm.getString(
+ "webXml.mergeConflictResource",
+ resourceName,
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ tempResources.put(resourceName, resource);
+ }
+ }
+ return true;
+ }
+
+ private static <T> boolean mergeMap(Map<String,T> fragmentMap,
+ Map<String,T> mainMap, Map<String,T> tempMap, WebXml fragment,
+ String mapName) {
+ for (Entry<String, T> entry : fragmentMap.entrySet()) {
+ final String key = entry.getKey();
+ if (!mainMap.containsKey(key)) {
+ // Not defined in main web.xml
+ T value = entry.getValue();
+ if (tempMap.containsKey(key)) {
+ if (value != null && !value.equals(
+ tempMap.get(key))) {
+ log.error(sm.getString(
+ "webXml.mergeConflictString",
+ mapName,
+ key,
+ fragment.getName(),
+ fragment.getURL()));
+ return false;
+ }
+ } else {
+ tempMap.put(key, value);
+ }
+ }
+ }
+ return true;
+ }
+
+ private static boolean mergeFilter(FilterDef src, FilterDef dest,
+ boolean failOnConflict) {
+ if (dest.getAsyncSupported() == null) {
+ dest.setAsyncSupported(src.getAsyncSupported());
+ } else if (src.getAsyncSupported() != null) {
+ if (failOnConflict &&
+ !src.getAsyncSupported().equals(dest.getAsyncSupported())) {
+ return false;
+ }
+ }
+
+ if (dest.getFilterClass() == null) {
+ dest.setFilterClass(src.getFilterClass());
+ } else if (src.getFilterClass() != null) {
+ if (failOnConflict &&
+ !src.getFilterClass().equals(dest.getFilterClass())) {
+ return false;
+ }
+ }
+
+ for (Map.Entry<String,String> srcEntry :
+ src.getParameterMap().entrySet()) {
+ if (dest.getParameterMap().containsKey(srcEntry.getKey())) {
+ if (failOnConflict && !dest.getParameterMap().get(
+ srcEntry.getKey()).equals(srcEntry.getValue())) {
+ return false;
+ }
+ } else {
+ dest.addInitParameter(srcEntry.getKey(), srcEntry.getValue());
+ }
+ }
+ return true;
+ }
+
+ private static boolean mergeServlet(ServletDef src, ServletDef dest,
+ boolean failOnConflict) {
+ // These tests should be unnecessary...
+ if (dest.getServletClass() != null && dest.getJspFile() != null) {
+ return false;
+ }
+ if (src.getServletClass() != null && src.getJspFile() != null) {
+ return false;
+ }
+
+
+ if (dest.getServletClass() == null && dest.getJspFile() == null) {
+ dest.setServletClass(src.getServletClass());
+ dest.setJspFile(src.getJspFile());
+ } else if (failOnConflict) {
+ if (src.getServletClass() != null &&
+ (dest.getJspFile() != null ||
+ !src.getServletClass().equals(dest.getServletClass()))) {
+ return false;
+ }
+ if (src.getJspFile() != null &&
+ (dest.getServletClass() != null ||
+ !src.getJspFile().equals(dest.getJspFile()))) {
+ return false;
+ }
+ }
+
+ // Additive
+ for (SecurityRoleRef securityRoleRef : src.getSecurityRoleRefs()) {
+ dest.addSecurityRoleRef(securityRoleRef);
+ }
+
+ if (dest.getLoadOnStartup() == null) {
+ if (src.getLoadOnStartup() != null) {
+ dest.setLoadOnStartup(src.getLoadOnStartup().toString());
+ }
+ } else if (src.getLoadOnStartup() != null) {
+ if (failOnConflict &&
+ !src.getLoadOnStartup().equals(dest.getLoadOnStartup())) {
+ return false;
+ }
+ }
+
+ if (dest.getEnabled() == null) {
+ if (src.getEnabled() != null) {
+ dest.setEnabled(src.getEnabled().toString());
+ }
+ } else if (src.getEnabled() != null) {
+ if (failOnConflict &&
+ !src.getEnabled().equals(dest.getEnabled())) {
+ return false;
+ }
+ }
+
+ for (Map.Entry<String,String> srcEntry :
+ src.getParameterMap().entrySet()) {
+ if (dest.getParameterMap().containsKey(srcEntry.getKey())) {
+ if (failOnConflict && !dest.getParameterMap().get(
+ srcEntry.getKey()).equals(srcEntry.getValue())) {
+ return false;
+ }
+ } else {
+ dest.addInitParameter(srcEntry.getKey(), srcEntry.getValue());
+ }
+ }
+
+ if (dest.getMultipartDef() == null) {
+ dest.setMultipartDef(src.getMultipartDef());
+ } else if (src.getMultipartDef() != null) {
+ return mergeMultipartDef(src.getMultipartDef(),
+ dest.getMultipartDef(), failOnConflict);
+ }
+
+ if (dest.getAsyncSupported() == null) {
+ if (src.getAsyncSupported() != null) {
+ dest.setAsyncSupported(src.getAsyncSupported().toString());
+ }
+ } else if (src.getAsyncSupported() != null) {
+ if (failOnConflict &&
+ !src.getAsyncSupported().equals(dest.getAsyncSupported())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static boolean mergeMultipartDef(MultipartDef src, MultipartDef dest,
+ boolean failOnConflict) {
+
+ if (dest.getLocation() == null) {
+ dest.setLocation(src.getLocation());
+ } else if (src.getLocation() != null) {
+ if (failOnConflict &&
+ !src.getLocation().equals(dest.getLocation())) {
+ return false;
+ }
+ }
+
+ if (dest.getFileSizeThreshold() == null) {
+ dest.setFileSizeThreshold(src.getFileSizeThreshold());
+ } else if (src.getFileSizeThreshold() != null) {
+ if (failOnConflict &&
+ !src.getFileSizeThreshold().equals(
+ dest.getFileSizeThreshold())) {
+ return false;
+ }
+ }
+
+ if (dest.getMaxFileSize() == null) {
+ dest.setMaxFileSize(src.getMaxFileSize());
+ } else if (src.getLocation() != null) {
+ if (failOnConflict &&
+ !src.getMaxFileSize().equals(dest.getMaxFileSize())) {
+ return false;
+ }
+ }
+
+ if (dest.getMaxRequestSize() == null) {
+ dest.setMaxRequestSize(src.getMaxRequestSize());
+ } else if (src.getMaxRequestSize() != null) {
+ if (failOnConflict &&
+ !src.getMaxRequestSize().equals(
+ dest.getMaxRequestSize())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Generates the sub-set of the web-fragment.xml files to be processed in
+ * the order that the fragments must be processed as per the rules in the
+ * Servlet spec.
+ *
+ * @param application The application web.xml file
+ * @param fragments The map of fragment names to web fragments
+ * @return Ordered list of web-fragment.xml files to process
+ */
+ public static Set<WebXml> orderWebFragments(WebXml application,
+ Map<String,WebXml> fragments) {
+
+ Set<WebXml> orderedFragments = new LinkedHashSet<WebXml>();
+
+ boolean absoluteOrdering =
+ (application.getAbsoluteOrdering() != null);
+
+ if (absoluteOrdering) {
+ // Only those fragments listed should be processed
+ Set<String> requestedOrder = application.getAbsoluteOrdering();
+
+ for (String requestedName : requestedOrder) {
+ if (WebXml.ORDER_OTHERS.equals(requestedName)) {
+ // Add all fragments not named explicitly at this point
+ for (Entry<String, WebXml> entry : fragments.entrySet()) {
+ if (!requestedOrder.contains(entry.getKey())) {
+ WebXml fragment = entry.getValue();
+ if (fragment != null) {
+ orderedFragments.add(fragment);
+ }
+ }
+ }
+ } else {
+ WebXml fragment = fragments.get(requestedName);
+ if (fragment != null) {
+ orderedFragments.add(fragment);
+ } else {
+ log.warn(sm.getString("webXml.wrongFragmentName",requestedName));
+ }
+ }
+ }
+ } else {
+ List<String> order = new LinkedList<String>();
+ // Start by adding all fragments - order doesn't matter
+ order.addAll(fragments.keySet());
+
+ // Now go through and move elements to start/end depending on if
+ // they specify others
+ for (WebXml fragment : fragments.values()) {
+ String name = fragment.getName();
+ if (fragment.getBeforeOrdering().contains(WebXml.ORDER_OTHERS)) {
+ // Move to beginning
+ order.remove(name);
+ order.add(0, name);
+ } else if (fragment.getAfterOrdering().contains(WebXml.ORDER_OTHERS)) {
+ // Move to end
+ order.remove(name);
+ order.add(name);
+ }
+ }
+
+ // Now apply remaining ordering
+ for (WebXml fragment : fragments.values()) {
+ String name = fragment.getName();
+ for (String before : fragment.getBeforeOrdering()) {
+ if (!before.equals(WebXml.ORDER_OTHERS) &&
+ order.contains(before) &&
+ order.indexOf(before) < order.indexOf(name)) {
+ order.remove(name);
+ order.add(order.indexOf(before), name);
+ }
+ }
+ for (String after : fragment.getAfterOrdering()) {
+ if (!after.equals(WebXml.ORDER_OTHERS) &&
+ order.contains(after) &&
+ order.indexOf(after) > order.indexOf(name)) {
+ order.remove(name);
+ order.add(order.indexOf(after) + 1, name);
+ }
+ }
+ }
+
+ // Finally check ordering was applied correctly - if there are
+ // errors then that indicates circular references
+ for (WebXml fragment : fragments.values()) {
+ String name = fragment.getName();
+ for (String before : fragment.getBeforeOrdering()) {
+ if (!before.equals(WebXml.ORDER_OTHERS) &&
+ order.contains(before) &&
+ order.indexOf(before) < order.indexOf(name)) {
+ throw new IllegalArgumentException(sm.getString(""));
+ }
+ }
+ for (String after : fragment.getAfterOrdering()) {
+ if (!after.equals(WebXml.ORDER_OTHERS) &&
+ order.contains(after) &&
+ order.indexOf(after) > order.indexOf(name)) {
+ throw new IllegalArgumentException();
+ }
+ }
+ }
+
+ // Build the ordered list
+ for (String name : order) {
+ orderedFragments.add(fragments.get(name));
+ }
+ }
+
+ return orderedFragments;
+ }
+
+}