From 62e1c71972806d98f89e716b8c2b349d74e09a8b Mon Sep 17 00:00:00 2001 From: markt Date: Fri, 23 Oct 2009 16:39:32 +0000 Subject: [PATCH] Add support for absolute ordering of web fragments and the start of the fragment merge code git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@829121 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/catalina/startup/ContextConfig.java | 85 ++++++++++++++++++---- .../catalina/startup/LocalStrings.properties | 19 +++-- java/org/apache/catalina/startup/WebRuleSet.java | 69 +++++++++++++++++- java/org/apache/catalina/startup/WebXml.java | 67 ++++++++++++++--- 4 files changed, 207 insertions(+), 33 deletions(-) diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java index 573ab069c..6afbd6c19 100644 --- a/java/org/apache/catalina/startup/ContextConfig.java +++ b/java/org/apache/catalina/startup/ContextConfig.java @@ -29,8 +29,10 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -1235,7 +1237,7 @@ public class ContextConfig if (!webXml.isMetadataComplete()) { // Have to process JARs for fragments - Map fragments = processJarsForWebFragments(); + Map fragments = processJarsForWebFragments(); // Merge the fragments into the main web.xml mergeWebFragments(webXml, fragments); @@ -1452,7 +1454,7 @@ public class ContextConfig * * @return A map of JAR name to processed web fragment (if any) */ - protected Map processJarsForWebFragments() { + protected Map processJarsForWebFragments() { JarScanner jarScanner = context.getJarScanner(); FragmentJarScannerCallback callback = new FragmentJarScannerCallback(); @@ -1467,7 +1469,7 @@ public class ContextConfig private static final String FRAGMENT_LOCATION = "META-INF/web-fragment.xml"; - private Map fragments = new HashMap(); + private Map fragments = new HashMap(); @Override public void scan(JarURLConnection urlConn) throws IOException { @@ -1505,7 +1507,15 @@ public class ContextConfig // ignore } } - fragments.put(urlConn.getURL(), fragment); + if (fragment == null) { + fragments.put(urlConn.getURL().toString(), fragment); + } else { + fragment.setURL(urlConn.getURL()); + if (fragment.getName() == null) { + fragment.setName(fragment.getURL().toString()); + } + fragments.put(fragment.getName(), fragment); + } } } @@ -1533,11 +1543,19 @@ public class ContextConfig // ignore } } - fragments.put(file.toURI().toURL(), fragment); + if (fragment == null) { + fragments.put(file.toURI().toURL().toString(), fragment); + } else { + fragment.setURL(file.toURI().toURL()); + if (fragment.getName() == null) { + fragment.setName(fragment.getURL().toString()); + } + fragments.put(fragment.getName(), fragment); + } } } - public Map getFragments() { + public Map getFragments() { return fragments; } } @@ -1547,22 +1565,61 @@ public class ContextConfig * Servlet spec. * * @param application The application web.xml file - * @param fragments The map of JARs to web fragments + * @param fragments The map of fragment names to web fragments */ protected void mergeWebFragments(WebXml application, - Map fragments) { - // TODO SERVLET3 - // Check order + Map fragments) { + + Set orderedFragments = new LinkedHashSet(); + + boolean absoluteOrdering = + (application.getAbsoluteOrdering() != null); + + if (absoluteOrdering) { + // Only those fragments listed should be processed + Set requestedOrder = application.getAbsoluteOrdering(); + + for (String requestedName : requestedOrder) { + if (WebXml.ORDER_OTHERS.equals(requestedName)) { + // Add all fragments not named explicitly at this point + for (String name : fragments.keySet()) { + if (!requestedOrder.contains(name)) { + WebXml fragment = fragments.get(name); + if (fragment != null) { + orderedFragments.add(fragment); + } + } + } + } else { + WebXml fragment = fragments.get(requestedName); + if (fragment != null) { + orderedFragments.add(fragment); + } + } + } + } else { + // TODO SERVLET3 Relative ordering + } // Merge fragments in order - conflict == error + WebXml mergedFragments = new WebXml(); + for (WebXml fragment : orderedFragments) { + ok = mergedFragments.merge(fragment, false); + if (ok == false) { + break; + } + } - // Merge fragment into application - conflict == application wins + // Merge fragment into application - conflict == application wins + if (ok) { + ok = application.merge(mergedFragments, true); + } } - protected void processAnnotationsInJars(Map fragments) { - for(URL url : fragments.keySet()) { - WebXml fragment = fragments.get(url); + protected void processAnnotationsInJars(Map fragments) { + for(String name : fragments.keySet()) { + WebXml fragment = fragments.get(name); if (fragment == null || !fragment.isMetadataComplete()) { // Scan jar for annotations // TODO SERVLET3 diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties index e69fd106d..07b0d850d 100644 --- a/java/org/apache/catalina/startup/LocalStrings.properties +++ b/java/org/apache/catalina/startup/LocalStrings.properties @@ -105,11 +105,14 @@ userConfig.deploying=Deploying user web applications userConfig.error=Error deploying web application for user {0} userConfig.start=UserConfig: Processing START userConfig.stop=UserConfig: Processing STOP -webXmlCommon.duplicateEnvEntry=Duplicate env-entry name -webXmlCommon.duplicateFilter=Duplicate filter name -webXmlCommon.duplicateMessageDestination=Duplicate message-destination name -webXmlCommon.duplicateMessageDestinationRef=Duplicate message-destination-ref name -webXmlCommon.duplicateResourceEnvRef=Duplicate resource-env-ref name -webXmlCommon.duplicateResourceRef=Duplicate resource-ref name -webXmlCommon.reservedName=A web.xml file was detected using a reserved name [{0}]. The name element will be ignored for this fragment. -webXmlFragment.multipleOther=Multiple others entries in ordering +webRuleSet.absoluteOrdering= element not valid in web-fragment.xml and will be ignored +webRuleSet.relativeOrdering= element not valid in web.xml and will be ignored +webXml.duplicateEnvEntry=Duplicate env-entry name +webXml.duplicateFilter=Duplicate filter name +webXml.duplicateMessageDestination=Duplicate message-destination name +webXml.duplicateMessageDestinationRef=Duplicate message-destination-ref name +webXml.duplicateResourceEnvRef=Duplicate resource-env-ref name +webXml.duplicateResourceRef=Duplicate resource-ref name +webXml.reservedName=A web.xml file was detected using a reserved name [{0}]. The name element will be ignored for this fragment. +webXml.mergeConflictListener=Listener [{0}] was defined in multiple fragments including fragment with name [{1}] located at [{2}] +webXml.multipleOther=Multiple others entries in ordering diff --git a/java/org/apache/catalina/startup/WebRuleSet.java b/java/org/apache/catalina/startup/WebRuleSet.java index 168ef0183..1bd9986b6 100644 --- a/java/org/apache/catalina/startup/WebRuleSet.java +++ b/java/org/apache/catalina/startup/WebRuleSet.java @@ -33,6 +33,7 @@ import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.digester.Rule; import org.apache.tomcat.util.digester.RuleSetBase; import org.apache.tomcat.util.digester.SetNextRule; +import org.apache.tomcat.util.res.StringManager; import org.xml.sax.Attributes; @@ -46,6 +47,11 @@ import org.xml.sax.Attributes; public class WebRuleSet extends RuleSetBase { + /** + * The string resources for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); // ----------------------------------------------------- Instance Variables @@ -62,6 +68,12 @@ public class WebRuleSet extends RuleSetBase { protected String fullPrefix = null; /** + * Flag that indicates if this ruleset is for a web-fragment.xml file or for + * a web.xml file. + */ + protected boolean fragment = false; + + /** * The SetSessionConfig rule used to parse the web.xml */ protected SetSessionConfig sessionConfig; @@ -116,13 +128,13 @@ public class WebRuleSet extends RuleSetBase { super(); this.namespaceURI = null; this.prefix = prefix; + this.fragment = fragment; if(fragment) { fullPrefix = prefix + "web-fragment"; } else { fullPrefix = prefix + "web-app"; } - } @@ -148,6 +160,31 @@ public class WebRuleSet extends RuleSetBase { digester.addRule(fullPrefix, new IgnoreAnnotationsRule()); + digester.addCallMethod(fullPrefix + "/name", + "setName", 0); + + if (fragment) { + // web-fragment.xml + digester.addRule(fullPrefix + "/absolute-ordering", + new AbsoluteOrderingRule()); + digester.addCallMethod(fullPrefix + "/ordering/after/name", + "addAfterOrdering", 0); + digester.addCallMethod(fullPrefix + "/ordering/after/others", + "addAfterOrderingOthers"); + digester.addCallMethod(fullPrefix + "/ordering/before/name", + "addBeforeOrdering", 0); + digester.addCallMethod(fullPrefix + "/ordering/before/others", + "addBeforeOrderingOthers"); + } else { + // web.xml + digester.addRule(fullPrefix + "/ordering", + new RelativeOrderingRule()); + digester.addCallMethod(fullPrefix + "/absolute-ordering/name", + "addAbsoluteOrdering", 0); + digester.addCallMethod(fullPrefix + "/absolute-ordering/name/others", + "addAbsoluteOrderingOthers"); + } + digester.addCallMethod(fullPrefix + "/context-param", "addContextParam", 2); digester.addCallParam(fullPrefix + "/context-param/param-name", 0); @@ -904,6 +941,36 @@ final class IgnoreAnnotationsRule extends Rule { } /** + * A rule that logs a warning if absolute ordering is configured. + */ +final class AbsoluteOrderingRule extends Rule { + + public AbsoluteOrderingRule() { + } + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + digester.getLogger().warn( + WebRuleSet.sm.getString("webRuleSet.absoluteOrdering")); + } +} + +/** + * A rule that logs a warning if relative ordering is configured. + */ +final class RelativeOrderingRule extends Rule { + + public RelativeOrderingRule() { + } + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + digester.getLogger().warn( + WebRuleSet.sm.getString("webRuleSet.relativeOrdering")); + } +} + +/** * A Rule that sets soap headers on the ContextHandler. * */ diff --git a/java/org/apache/catalina/startup/WebXml.java b/java/org/apache/catalina/startup/WebXml.java index 1fb6b0b2a..0eb84f5f1 100644 --- a/java/org/apache/catalina/startup/WebXml.java +++ b/java/org/apache/catalina/startup/WebXml.java @@ -18,6 +18,7 @@ package org.apache.catalina.startup; +import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; @@ -65,13 +66,22 @@ public class WebXml { // web.xml only elements // Absolute Ordering - private Set absoluteOrdering = new LinkedHashSet(); + private Set absoluteOrdering = null; public void addAbsoluteOrdering(String name) { + if (absoluteOrdering == null) { + absoluteOrdering = new LinkedHashSet(); + } absoluteOrdering.add(name); } public void addAbsoluteOrderingOthers() { + if (absoluteOrdering == null) { + absoluteOrdering = new LinkedHashSet(); + } absoluteOrdering.add(ORDER_OTHERS); } + public Set getAbsoluteOrdering() { + return absoluteOrdering; + } // web-fragment.xml only elements // Relative ordering @@ -82,7 +92,7 @@ public class WebXml { public void addAfterOrderingOthers() { if (before.contains(ORDER_OTHERS)) { throw new IllegalArgumentException(sm.getString( - "webXmlFragment.multipleOther")); + "webXml.multipleOther")); } after.add(ORDER_OTHERS); } @@ -93,7 +103,7 @@ public class WebXml { public void addBeforeOrderingOthers() { if (after.contains(ORDER_OTHERS)) { throw new IllegalArgumentException(sm.getString( - "webXmlFragment.multipleOther")); + "webXml.multipleOther")); } before.add(ORDER_OTHERS); } @@ -122,7 +132,7 @@ public class WebXml { 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("webXmlCommon.reservedName", name)); + log.warn(sm.getString("webXml.reservedName", name)); } else { this.name = name; } @@ -165,7 +175,7 @@ public class WebXml { if (filters.containsKey(filter.getFilterName())) { // Filter names must be unique within a web(-fragment).xml throw new IllegalArgumentException( - sm.getString("webXmlCommon.duplicateFilter")); + sm.getString("webXml.duplicateFilter")); } filters.put(filter.getFilterName(), filter); } @@ -299,7 +309,7 @@ public class WebXml { if (envEntries.containsKey(envEntry.getName())) { // env-entry names must be unique within a web(-fragment).xml throw new IllegalArgumentException( - sm.getString("webXmlCommon.duplicateEnvEntry")); + sm.getString("webXml.duplicateEnvEntry")); } envEntries.put(envEntry.getName(),envEntry); } @@ -337,7 +347,7 @@ public class WebXml { if (resourceRefs.containsKey(resourceRef.getName())) { // resource-ref names must be unique within a web(-fragment).xml throw new IllegalArgumentException( - sm.getString("webXmlCommon.duplicateResourceRef")); + sm.getString("webXml.duplicateResourceRef")); } resourceRefs.put(resourceRef.getName(), resourceRef); } @@ -353,7 +363,7 @@ public class WebXml { if (resourceEnvRefs.containsKey(resourceEnvRef.getName())) { // resource-env-ref names must be unique within a web(-fragment).xml throw new IllegalArgumentException( - sm.getString("webXmlCommon.duplicateResourceEnvRef")); + sm.getString("webXml.duplicateResourceEnvRef")); } resourceEnvRefs.put(resourceEnvRef.getName(), resourceEnvRef); } @@ -372,7 +382,7 @@ public class WebXml { // message-destination-ref names must be unique within a // web(-fragment).xml throw new IllegalArgumentException(sm.getString( - "webXmlCommon.duplicateMessageDestinationRef")); + "webXml.duplicateMessageDestinationRef")); } messageDestinationRefs.put(messageDestinationRef.getName(), messageDestinationRef); @@ -394,7 +404,7 @@ public class WebXml { // message-destination names must be unique within a // web(-fragment).xml throw new IllegalArgumentException( - sm.getString("webXmlCommon.duplicateMessageDestination")); + sm.getString("webXml.duplicateMessageDestination")); } messageDestinations.put(messageDestination.getName(), messageDestination); @@ -413,6 +423,14 @@ public class WebXml { return localeEncodingMappings; } + + // Attributes not defined in web.xml or web-fragment.xml + + // URL of web-fragment + private URL uRL = null; + public void setURL(URL url) { this.uRL = url; } + public URL getURL() { return uRL; } + /** * Configure a {@link Context} using the stored web.xml representation. * @@ -538,4 +556,33 @@ public class WebXml { context.addJspMapping(jspPropertyGroup.getUrlPattern()); } } + + /** + * Merge the supplied web fragment into this this one. + * + * @param source The fragment to merge in + * @boolean ignoreConflicts Flag that indicates that conflicts should be + * ignored and the existing value used + * @return true if merge is successful, else + * false + */ + public boolean merge(WebXml source, boolean ignoreConflicts) { + // TODO SERVLET3 + + // Just do listeners for now since that is what my simple test case is + // using + for (String listener : source.getListeners()) { + if (listeners.contains(listener)) { + if (!ignoreConflicts) { + log.error(sm.getString("webXml.mergeConflictListener", + listener, source.getName(), source.getURL())); + return false; + } + } else { + listeners.add(listener); + } + } + + return true; + } } -- 2.11.0