in java/org/apache/tomcat/util/descriptor/web/WebXml.java [1457:1885]
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();
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();
}
// Note: Not permitted in fragments, but we also use fragments for
// per-Host and global defaults so they may appear there
if (!denyUncoveredHttpMethods) {
for (WebXml fragment : fragments) {
if (fragment.getDenyUncoveredHttpMethods()) {
denyUncoveredHttpMethods = true;
break;
}
}
}
if (requestCharacterEncoding == null) {
for (WebXml fragment : fragments) {
if (fragment.getRequestCharacterEncoding() != null) {
requestCharacterEncoding = fragment.getRequestCharacterEncoding();
}
}
}
if (responseCharacterEncoding == null) {
for (WebXml fragment : fragments) {
if (fragment.getResponseCharacterEncoding() != null) {
responseCharacterEncoding = fragment.getResponseCharacterEncoding();
}
}
}
if (distributable) {
for (WebXml fragment : fragments) {
if (!fragment.isDistributable()) {
distributable = false;
break;
}
}
}
for (WebXml fragment : fragments) {
if (!mergeResourceMap(fragment.getEjbLocalRefs(), ejbLocalRefs,
temp.getEjbLocalRefs(), fragment)) {
return false;
}
}
ejbLocalRefs.putAll(temp.getEjbLocalRefs());
for (WebXml fragment : fragments) {
if (!mergeResourceMap(fragment.getEjbRefs(), ejbRefs,
temp.getEjbRefs(), fragment)) {
return false;
}
}
ejbRefs.putAll(temp.getEjbRefs());
for (WebXml fragment : fragments) {
if (!mergeResourceMap(fragment.getEnvEntries(), envEntries,
temp.getEnvEntries(), fragment)) {
return false;
}
}
envEntries.putAll(temp.getEnvEntries());
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<>();
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.getLocaleEncodingMappings(),
localeEncodingMappings, temp.getLocaleEncodingMappings(),
fragment, "Locale Encoding Mapping")) {
return false;
}
}
localeEncodingMappings.putAll(temp.getLocaleEncodingMappings());
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(), fragment)) {
return false;
}
}
messageDestinationRefs.putAll(temp.getMessageDestinationRefs());
for (WebXml fragment : fragments) {
if (!mergeResourceMap(fragment.getMessageDestinations(), messageDestinations,
temp.getMessageDestinations(), fragment)) {
return false;
}
}
messageDestinations.putAll(temp.getMessageDestinations());
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(), fragment)) {
return false;
}
}
resourceEnvRefs.putAll(temp.getResourceEnvRefs());
for (WebXml fragment : fragments) {
if (!mergeResourceMap(fragment.getResourceRefs(), resourceRefs,
temp.getResourceRefs(), fragment)) {
return false;
}
}
resourceRefs.putAll(temp.getResourceRefs());
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(), fragment)) {
return false;
}
}
serviceRefs.putAll(temp.getServiceRefs());
// 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<>();
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) {
addServletMappingDecoded(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());
}
Map<String,String> mainAttributes = getSessionConfig().getCookieAttributes();
Map<String,String> mergedFragmentAttributes = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (WebXml fragment : fragments) {
for (Map.Entry<String,String> attribute : fragment.getSessionConfig().getCookieAttributes().entrySet()) {
// Skip any attribute in a fragment that is defined in the main web.xml
if (!mainAttributes.containsKey(attribute.getKey())) {
if (mergedFragmentAttributes.containsKey(attribute.getKey())) {
// Attribute has already been seen.
// If values are the same, NO-OP. If they are different
// trigger a merge error
if (!mergedFragmentAttributes.get(attribute.getKey()).equals(attribute.getValue())) {
log.error(sm.getString(
"webXml.mergeConflictSessionCookieAttributes",
fragment.getName(),
fragment.getURL()));
return false;
}
} else {
// First time this attribute has been seen. Add it.
mergedFragmentAttributes.put(attribute.getKey(), attribute.getValue());
}
}
}
}
mainAttributes.putAll(mergedFragmentAttributes);
if (sessionConfig.getSessionTrackingModes().isEmpty()) {
for (WebXml fragment : fragments) {
EnumSet<SessionTrackingMode> value =
fragment.getSessionConfig().getSessionTrackingModes();
if (!value.isEmpty()) {
if (temp.getSessionConfig().getSessionTrackingModes().isEmpty()) {
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.isEmpty()) {
for (String welcomeFile : fragment.getWelcomeFiles()) {
addWelcomeFile(welcomeFile);
}
}
}
if (postConstructMethods.isEmpty()) {
for (WebXml fragment : fragments) {
if (!mergeLifecycleCallback(fragment.getPostConstructMethods(),
temp.getPostConstructMethods(), fragment,
"Post Construct Methods")) {
return false;
}
}
postConstructMethods.putAll(temp.getPostConstructMethods());
}
if (preDestroyMethods.isEmpty()) {
for (WebXml fragment : fragments) {
if (!mergeLifecycleCallback(fragment.getPreDestroyMethods(),
temp.getPreDestroyMethods(), fragment,
"Pre Destroy Methods")) {
return false;
}
}
preDestroyMethods.putAll(temp.getPreDestroyMethods());
}
return true;
}