Skip to content
55 changes: 41 additions & 14 deletions java/org/apache/tomcat/util/descriptor/web/ContextService.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package org.apache.tomcat.util.descriptor.web;

import java.io.Serial;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


Expand All @@ -42,26 +44,55 @@ public ContextService() {


/**
* The WebService reference name.
* The WebService reference display names. Multiple display names, each with an optional language, are supported as
* per the deployment descriptor specification.
*/
private String displayname = null;
private final List<LocaleElement> displaynames = new ArrayList<>();

/**
* Returns the WebService reference display name.
* Returns the WebService reference display names.
*
* @return the display names
*/
public List<LocaleElement> getDisplaynames() {
return displaynames;
}

/**
* Adds a WebService reference display name.
*
* @param displayname the display name to add
*/
public void addDisplayname(LocaleElement displayname) {
displaynames.add(displayname);
}

/**
* Returns the WebService reference display name. The default display name (the one without a language) is
* returned if present, otherwise the first display name is returned.
*
* @return the display name
*/
public String getDisplayname() {
return this.displayname;
for (LocaleElement element : displaynames) {
if (element.getLang() == null) {
return element.getContent();
}
}
return displaynames.isEmpty() ? null : displaynames.get(0).getContent();
}

/**
* Sets the WebService reference display name.
* Sets the WebService reference display name. Any existing display names, including language specific ones, are
* replaced by a single default display name.
*
* @param displayname the display name
*/
public void setDisplayname(String displayname) {
this.displayname = displayname;
displaynames.clear();
if (displayname != null) {
displaynames.add(new LocaleElement(displayname, null));
}
}

/**
Expand Down Expand Up @@ -352,9 +383,9 @@ public String toString() {
sb.append(", type=");
sb.append(getType());
}
if (displayname != null) {
if (getDisplayname() != null) {
sb.append(", displayname=");
sb.append(displayname);
sb.append(getDisplayname());
}
if (largeIcon != null) {
sb.append(", largeIcon=");
Expand Down Expand Up @@ -403,7 +434,7 @@ public String toString() {
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((displayname == null) ? 0 : displayname.hashCode());
result = prime * result + displaynames.hashCode();
result = prime * result + handlers.hashCode();
result = prime * result + ((jaxrpcmappingfile == null) ? 0 : jaxrpcmappingfile.hashCode());
result = prime * result + ((largeIcon == null) ? 0 : largeIcon.hashCode());
Expand All @@ -427,11 +458,7 @@ public boolean equals(Object obj) {
return false;
}
ContextService other = (ContextService) obj;
if (displayname == null) {
if (other.displayname != null) {
return false;
}
} else if (!displayname.equals(other.displayname)) {
if (!displaynames.equals(other.displaynames)) {
return false;
}
if (!handlers.equals(other.handlers)) {
Expand Down
84 changes: 72 additions & 12 deletions java/org/apache/tomcat/util/descriptor/web/FilterDef.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jakarta.servlet.Filter;
Expand Down Expand Up @@ -48,50 +50,108 @@ public FilterDef() {


/**
* The description of this filter.
* The descriptions of this filter. Multiple descriptions, each with an optional language, are supported as per the
* deployment descriptor specification.
*/
private String description = null;
private final List<LocaleElement> descriptions = new ArrayList<>();

/**
* Returns the description of this filter.
* Returns the descriptions of this filter.
*
* @return The descriptions
*/
public List<LocaleElement> getDescriptions() {
return descriptions;
}

/**
* Adds a description to this filter.
*
* @param description The description to add
*/
public void addDescription(LocaleElement description) {
descriptions.add(description);
}

/**
* Returns the description of this filter. The default description (the one without a language) is returned if
* present, otherwise the first description is returned.
*
* @return The description
*/
public String getDescription() {
return this.description;
for (LocaleElement element : descriptions) {
if (element.getLang() == null) {
return element.getContent();
}
}
return descriptions.isEmpty() ? null : descriptions.get(0).getContent();
}

/**
* Sets the description of this filter.
* Sets the description of this filter. Any existing descriptions, including language specific ones, are replaced
* by a single default description.
*
* @param description The new description
*/
public void setDescription(String description) {
this.description = description;
descriptions.clear();
if (description != null) {
descriptions.add(new LocaleElement(description, null));
}
}


/**
* The display name of this filter.
* The display names of this filter. Multiple display names, each with an optional language, are supported as per
* the deployment descriptor specification.
*/
private String displayName = null;
private final List<LocaleElement> displayNames = new ArrayList<>();

/**
* Returns the display name of this filter.
* Returns the display names of this filter.
*
* @return The display names
*/
public List<LocaleElement> getDisplayNames() {
return displayNames;
}

/**
* Adds a display name to this filter.
*
* @param displayName The display name to add
*/
public void addDisplayName(LocaleElement displayName) {
displayNames.add(displayName);
}

/**
* Returns the display name of this filter. The default display name (the one without a language) is returned if
* present, otherwise the first display name is returned.
*
* @return The display name
*/
public String getDisplayName() {
return this.displayName;
for (LocaleElement element : displayNames) {
if (element.getLang() == null) {
return element.getContent();
}
}
return displayNames.isEmpty() ? null : displayNames.get(0).getContent();
}

/**
* Sets the display name of this filter.
* Sets the display name of this filter. Any existing display names, including language specific ones, are replaced
* by a single default display name.
*
* @param displayName The new display name
*/
public void setDisplayName(String displayName) {
this.displayName = displayName;
displayNames.clear();
if (displayName != null) {
displayNames.add(new LocaleElement(displayName, null));
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ webXml.duplicateResourceEnvRef=Duplicate resource-env-ref name [{0}]
webXml.duplicateResourceRef=Duplicate resource-ref name [{0}]
webXml.duplicateServletMapping=The servlets named [{0}] and [{1}] are both mapped to the url-pattern [{2}] which is not permitted
webXml.duplicateTaglibUri=Duplicate tag library URI [{0}]
webXml.mergeConflictDescription=The description was defined in multiple fragments with different values including fragment with name [{0}] located at [{1}]
webXml.mergeConflictDisplayName=The display name was defined in multiple fragments with different values including fragment with name [{0}] located at [{1}]
webXml.mergeConflictFilter=The Filter [{0}] was defined inconsistently in multiple fragments including fragment with name [{1}] located at [{2}]
webXml.mergeConflictLoginConfig=A LoginConfig was defined inconsistently in multiple fragments including fragment with name [{0}] located at [{1}]
Expand Down
122 changes: 122 additions & 0 deletions java/org/apache/tomcat/util/descriptor/web/LocaleElement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* 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.tomcat.util.descriptor.web;

import java.io.Serial;
import java.io.Serializable;

/**
* Represents an element of a deployment descriptor that supports internationalization (i18n) via the optional
* {@code xml:lang} attribute, for example {@code <description>} and {@code <display-name>}.
* <p>
* The {@code content} holds the element body text. The {@code lang} holds the value of the optional {@code xml:lang}
* attribute, or {@code null} if the attribute is absent. An element without a {@code lang} is the default element
* that applies when no language specific element matches.
* </p>
*/
public class LocaleElement implements Serializable {

@Serial
private static final long serialVersionUID = 1L;

/**
* The content of the element.
*/
private final String content;

/**
* The value of the {@code xml:lang} attribute, or {@code null} if not specified.
*/
private final String lang;

/**
* Creates a new LocaleElement.
*
* @param content The element content
* @param lang The value of the {@code xml:lang} attribute, or {@code null} if not specified
*/
public LocaleElement(String content, String lang) {
this.content = content;
this.lang = lang;
}

/**
* Returns the content of the element.
*
* @return The element content
*/
public String getContent() {
return content;
}

/**
* Returns the value of the {@code xml:lang} attribute, or {@code null} if not specified.
*
* @return The {@code xml:lang} attribute value
*/
public String getLang() {
return lang;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((content == null) ? 0 : content.hashCode());
result = prime * result + ((lang == null) ? 0 : lang.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
LocaleElement other = (LocaleElement) obj;
if (content == null) {
if (other.content != null) {
return false;
}
} else if (!content.equals(other.content)) {
return false;
}
if (lang == null) {
return other.lang == null;
} else {
return lang.equals(other.lang);
}
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder("LocaleElement[");
sb.append("content=");
sb.append(content);
if (lang != null) {
sb.append(", lang=");
sb.append(lang);
}
sb.append(']');
return sb.toString();
}
}
Loading