You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2019/03/07 20:22:32 UTC
[tomcat] branch 7.0.x updated: Fix
https://bz.apache.org/bugzilla/show_bug.cgi?id=63236
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch 7.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/7.0.x by this push:
new 25b1c2c Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63236
25b1c2c is described below
commit 25b1c2c5b98d5cc2581a8a35249b2796558586be
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Mar 7 19:36:43 2019 +0000
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63236
Use intern() as suggested by Phillip Webb to reduce memory wasted due to
string duplication. Saves ~254k on a clean install.
Thanks to YourKit for helping to track these down.
---
.../apache/catalina/util/LifecycleMBeanBase.java | 2 +-
.../tomcat/util/digester/CallMethodRule.java | 2 +-
java/org/apache/tomcat/util/digester/Digester.java | 233 ++++++++++-----------
.../apache/tomcat/util/modeler/ManagedBean.java | 50 ++---
.../MbeansDescriptorsIntrospectionSource.java | 4 +-
webapps/docs/changelog.xml | 7 +
6 files changed, 150 insertions(+), 148 deletions(-)
diff --git a/java/org/apache/catalina/util/LifecycleMBeanBase.java b/java/org/apache/catalina/util/LifecycleMBeanBase.java
index 2939d92..4ff80d5 100644
--- a/java/org/apache/catalina/util/LifecycleMBeanBase.java
+++ b/java/org/apache/catalina/util/LifecycleMBeanBase.java
@@ -238,7 +238,7 @@ public abstract class LifecycleMBeanBase extends LifecycleBase
this.mserver = server;
this.oname = name;
- this.domain = name.getDomain();
+ this.domain = name.getDomain().intern();
return oname;
}
diff --git a/java/org/apache/tomcat/util/digester/CallMethodRule.java b/java/org/apache/tomcat/util/digester/CallMethodRule.java
index 4350ecc..8da692a 100644
--- a/java/org/apache/tomcat/util/digester/CallMethodRule.java
+++ b/java/org/apache/tomcat/util/digester/CallMethodRule.java
@@ -404,7 +404,7 @@ public class CallMethodRule extends Rule {
throws Exception {
if (paramCount == 0) {
- this.bodyText = bodyText.trim();
+ this.bodyText = bodyText.trim().intern();
}
}
diff --git a/java/org/apache/tomcat/util/digester/Digester.java b/java/org/apache/tomcat/util/digester/Digester.java
index dc92d90..f427b5b 100644
--- a/java/org/apache/tomcat/util/digester/Digester.java
+++ b/java/org/apache/tomcat/util/digester/Digester.java
@@ -5,15 +5,15 @@
* 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.digester;
@@ -200,12 +200,12 @@ public class Digester extends DefaultHandler2 {
* in the input is entered, the matching rules are pushed onto this
* stack. After the end tag is reached, the matches are popped again.
* The depth of is stack is therefore exactly the same as the current
- * "nesting" level of the input xml.
+ * "nesting" level of the input xml.
*
* @since 1.6
*/
protected ArrayStack<List<Rule>> matches = new ArrayStack<List<Rule>>(10);
-
+
/**
* The class loader to use for instantiating application objects.
* If not specified, the context class loader, or the class loader
@@ -225,7 +225,7 @@ public class Digester extends DefaultHandler2 {
* The EntityResolver used by the SAX parser. By default it use this class
*/
protected EntityResolver entityResolver;
-
+
/**
* The URLs of entityValidator that have been registered, keyed by the public
* identifier that corresponds.
@@ -341,7 +341,7 @@ public class Digester extends DefaultHandler2 {
*/
protected boolean rulesValidation = false;
-
+
/**
* Fake attributes map (attributes are often used for object creation).
*/
@@ -360,12 +360,12 @@ public class Digester extends DefaultHandler2 {
*/
protected Log saxLog =
LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax");
-
-
+
+
/** Stacks used for interrule communication, indexed by name String */
private HashMap<String,ArrayStack<Object>> stacksByName =
new HashMap<String,ArrayStack<Object>>();
-
+
// ------------------------------------------------------------- Properties
/**
@@ -376,7 +376,7 @@ public class Digester extends DefaultHandler2 {
* @param prefix Prefix to look up
*/
public String findNamespaceURI(String prefix) {
-
+
ArrayStack<String> stack = namespaces.get(prefix);
if (stack == null) {
return (null);
@@ -480,9 +480,9 @@ public class Digester extends DefaultHandler2 {
/**
* Return the SAXParserFactory we will use, creating one if necessary.
- * @throws ParserConfigurationException
- * @throws SAXNotSupportedException
- * @throws SAXNotRecognizedException
+ * @throws ParserConfigurationException
+ * @throws SAXNotSupportedException
+ * @throws SAXNotRecognizedException
*/
public SAXParserFactory getFactory()
throws SAXNotRecognizedException, SAXNotSupportedException,
@@ -596,10 +596,10 @@ public class Digester extends DefaultHandler2 {
* @since 1.6
*/
public Log getSAXLogger() {
-
+
return saxLog;
}
-
+
/**
* Sets the logger used for logging SAX-related information.
@@ -607,9 +607,9 @@ public class Digester extends DefaultHandler2 {
* @param saxLog Log, not null
*
* @since 1.6
- */
+ */
public void setSAXLogger(Log saxLog) {
-
+
this.saxLog = saxLog;
}
@@ -644,7 +644,7 @@ public class Digester extends DefaultHandler2 {
}
-
+
/**
* Set the public id of the current file being parse.
* @param publicId the DTD/Schema public's id.
@@ -652,8 +652,8 @@ public class Digester extends DefaultHandler2 {
public void setPublicId(String publicId){
this.publicId = publicId;
}
-
-
+
+
/**
* Return the public identifier of the DTD we are currently
* parsing under, if any.
@@ -775,7 +775,7 @@ public class Digester extends DefaultHandler2 {
}
-
+
/**
* Set the <code>Rules</code> implementation object containing our
* rules collection and associated matching policy.
@@ -908,24 +908,24 @@ public class Digester extends DefaultHandler2 {
/**
* Return the XMLReader to be used for parsing the input document.
*
- * FIX ME: there is a bug in JAXP/XERCES that prevent the use of a
+ * FIX ME: there is a bug in JAXP/XERCES that prevent the use of a
* parser that contains a schema with a DTD.
* @exception SAXException if no XMLReader can be instantiated
*/
public XMLReader getXMLReader() throws SAXException {
if (reader == null){
reader = getParser().getXMLReader();
- }
-
- reader.setDTDHandler(this);
- reader.setContentHandler(this);
-
+ }
+
+ reader.setDTDHandler(this);
+ reader.setContentHandler(this);
+
if (entityResolver == null){
reader.setEntityResolver(this);
} else {
- reader.setEntityResolver(entityResolver);
+ reader.setEntityResolver(entityResolver);
}
-
+
reader.setProperty(
"http://xml.org/sax/properties/lexical-handler", this);
@@ -1031,7 +1031,7 @@ public class Digester extends DefaultHandler2 {
// Parse system properties
bodyText = updateBodyText(bodyText);
- // the actual element name is either in localName or qName, depending
+ // the actual element name is either in localName or qName, depending
// on whether the parser is namespace aware
String name = localName;
if ((name == null) || (name.length() < 1)) {
@@ -1041,7 +1041,7 @@ public class Digester extends DefaultHandler2 {
// Fire "body" events for all relevant rules
List<Rule> rules = matches.pop();
if ((rules != null) && (rules.size() > 0)) {
- String bodyText = this.bodyText.toString();
+ String bodyText = this.bodyText.toString().intern();
for (int i = 0; i < rules.size(); i++) {
try {
Rule rule = rules.get(i);
@@ -1234,7 +1234,7 @@ public class Digester extends DefaultHandler2 {
saxLog.debug("startDocument()");
}
- // ensure that the digester is properly configured, as
+ // ensure that the digester is properly configured, as
// the digester could be used as a SAX ContentHandler
// rather than via the parse() methods.
configure();
@@ -1251,7 +1251,7 @@ public class Digester extends DefaultHandler2 {
* @param qName The qualified name (with prefix), or the empty
* string if qualified names are not available.\
* @param list The attributes attached to the element. If there are
- * no attributes, it shall be an empty Attributes object.
+ * no attributes, it shall be an empty Attributes object.
* @exception SAXException if a parsing error is to be reported
*/
@Override
@@ -1259,20 +1259,20 @@ public class Digester extends DefaultHandler2 {
String qName, Attributes list)
throws SAXException {
boolean debug = log.isDebugEnabled();
-
+
if (saxLog.isDebugEnabled()) {
saxLog.debug("startElement(" + namespaceURI + "," + localName + "," +
qName + ")");
}
-
+
// Parse system properties
list = updateAttributes(list);
-
+
// Save the body text accumulated for our surrounding element
bodyTexts.push(bodyText);
bodyText = new StringBuilder();
- // the actual element name is either in localName or qName, depending
+ // the actual element name is either in localName or qName, depending
// on whether the parser is namespace aware
String name = localName;
if ((name == null) || (name.length() < 1)) {
@@ -1397,8 +1397,8 @@ public class Digester extends DefaultHandler2 {
public void setEntityResolver(EntityResolver entityResolver){
this.entityResolver = entityResolver;
}
-
-
+
+
/**
* Return the Entity Resolver used by the SAX parser.
* @return Return the Entity Resolver used by the SAX parser.
@@ -1415,27 +1415,27 @@ public class Digester extends DefaultHandler2 {
saxLog.debug("resolveEntity('" + publicId + "', '" + systemId +
"', '" + baseURI + "')");
}
-
+
// Has this system identifier been registered?
String entityURL = null;
if (publicId != null) {
entityURL = entityValidator.get(publicId);
}
-
- if (entityURL == null) {
+
+ if (entityURL == null) {
if (systemId == null) {
// cannot resolve
if (log.isDebugEnabled()) {
log.debug(" Cannot resolve entity: '" + publicId + "'");
}
return (null);
-
+
} else {
// try to resolve using system ID
if (log.isDebugEnabled()) {
log.debug(" Trying to resolve using system ID '" +
systemId + "'");
- }
+ }
entityURL = systemId;
// resolve systemId against baseURI if it is not absolute
if (baseURI != null) {
@@ -1453,12 +1453,12 @@ public class Digester extends DefaultHandler2 {
}
}
}
-
+
// Return an input source to our alternative URL
if (log.isDebugEnabled()) {
log.debug(" Resolving to alternate DTD '" + entityURL + "'");
- }
-
+ }
+
try {
return (new InputSource(entityURL));
} catch (Exception e) {
@@ -1534,7 +1534,7 @@ public class Digester extends DefaultHandler2 {
log.warn("Parse Warning Error at line " + exception.getLineNumber() +
" column " + exception.getColumnNumber() + ": " +
exception.getMessage(), exception);
-
+
errorHandler.warning(exception);
}
@@ -1560,7 +1560,7 @@ public class Digester extends DefaultHandler2 {
getXMLReader().parse(input);
return (root);
- }
+ }
/**
* Parse the content of the specified input source using this Digester.
* Returns the root element from the object stack (if any).
@@ -1571,7 +1571,7 @@ public class Digester extends DefaultHandler2 {
* @exception SAXException if a parsing exception occurs
*/
public Object parse(InputSource input) throws IOException, SAXException {
-
+
configure();
getXMLReader().parse(input);
return (root);
@@ -1641,18 +1641,18 @@ public class Digester extends DefaultHandler2 {
* This must be called before the first call to <code>parse()</code>.
* </p><p>
* <code>Digester</code> contains an internal <code>EntityResolver</code>
- * implementation. This maps <code>PUBLICID</code>'s to URLs
+ * implementation. This maps <code>PUBLICID</code>'s to URLs
* (from which the resource will be loaded). A common use case for this
- * method is to register local URLs (possibly computed at runtime by a
+ * method is to register local URLs (possibly computed at runtime by a
* classloader) for DTDs. This allows the performance advantage of using
* a local version without having to ensure every <code>SYSTEM</code>
* URI on every processed xml document is local. This implementation provides
* only basic functionality. If more sophisticated features are required,
* using {@link #setEntityResolver} to set a custom resolver is recommended.
* </p><p>
- * <strong>Note:</strong> This method will have no effect when a custom
- * <code>EntityResolver</code> has been set. (Setting a custom
- * <code>EntityResolver</code> overrides the internal implementation.)
+ * <strong>Note:</strong> This method will have no effect when a custom
+ * <code>EntityResolver</code> has been set. (Setting a custom
+ * <code>EntityResolver</code> overrides the internal implementation.)
* </p>
* @param publicId Public identifier of the DTD to be resolved
* @param entityURL The URL to use for reading this DTD
@@ -1765,7 +1765,7 @@ public class Digester extends DefaultHandler2 {
addRule(pattern,
new CallMethodRule(
methodName,
- paramCount,
+ paramCount,
paramTypes));
}
@@ -1794,7 +1794,7 @@ public class Digester extends DefaultHandler2 {
addRule(pattern,
new CallMethodRule(
methodName,
- paramCount,
+ paramCount,
paramTypes));
}
@@ -1837,18 +1837,18 @@ public class Digester extends DefaultHandler2 {
/**
* Add a "call parameter" rule.
- * This will either take a parameter from the stack
- * or from the current element body text.
+ * This will either take a parameter from the stack
+ * or from the current element body text.
*
* @param paramIndex The zero-relative parameter number
* @param fromStack Should the call parameter be taken from the top of the stack?
* @see CallParamRule
- */
+ */
public void addCallParam(String pattern, int paramIndex, boolean fromStack) {
-
+
addRule(pattern,
new CallParamRule(paramIndex, fromStack));
-
+
}
/**
@@ -1859,16 +1859,16 @@ public class Digester extends DefaultHandler2 {
* @param stackIndex set the call parameter to the stackIndex'th object down the stack,
* where 0 is the top of the stack, 1 the next element down and so on
* @see CallMethodRule
- */
+ */
public void addCallParam(String pattern, int paramIndex, int stackIndex) {
-
+
addRule(pattern,
new CallParamRule(paramIndex, stackIndex));
-
+
}
-
+
/**
- * Add a "call parameter" rule that sets a parameter from the current
+ * Add a "call parameter" rule that sets a parameter from the current
* <code>Digester</code> matching path.
* This is sometimes useful when using rules that support wildcards.
*
@@ -1879,9 +1879,9 @@ public class Digester extends DefaultHandler2 {
public void addCallParamPath(String pattern,int paramIndex) {
addRule(pattern, new PathCallParamRule(paramIndex));
}
-
+
/**
- * Add a "call parameter" rule that sets a parameter from a
+ * Add a "call parameter" rule that sets a parameter from a
* caller-provided object. This can be used to pass constants such as
* strings to methods; it can also be used to pass mutable objects,
* providing ways for objects to do things like "register" themselves
@@ -1899,15 +1899,15 @@ public class Digester extends DefaultHandler2 {
* @see CallMethodRule
*
* @since 1.6
- */
- public void addObjectParam(String pattern, int paramIndex,
+ */
+ public void addObjectParam(String pattern, int paramIndex,
Object paramObj) {
-
+
addRule(pattern,
new ObjectParamRule(paramIndex, paramObj));
-
+
}
-
+
/**
* Add a "factory create" rule for the specified parameters.
* Exceptions thrown during the object creation process will be propagated.
@@ -2000,7 +2000,7 @@ public class Digester extends DefaultHandler2 {
* @see FactoryCreateRule
*/
public void addFactoryCreate(
- String pattern,
+ String pattern,
String className,
boolean ignoreCreateExceptions) {
@@ -2021,7 +2021,7 @@ public class Digester extends DefaultHandler2 {
* @see FactoryCreateRule
*/
public void addFactoryCreate(
- String pattern,
+ String pattern,
Class<?> clazz,
boolean ignoreCreateExceptions) {
@@ -2044,7 +2044,7 @@ public class Digester extends DefaultHandler2 {
* @see FactoryCreateRule
*/
public void addFactoryCreate(
- String pattern,
+ String pattern,
String className,
String attributeName,
boolean ignoreCreateExceptions) {
@@ -2068,7 +2068,7 @@ public class Digester extends DefaultHandler2 {
* @see FactoryCreateRule
*/
public void addFactoryCreate(
- String pattern,
+ String pattern,
Class<?> clazz,
String attributeName,
boolean ignoreCreateExceptions) {
@@ -2255,7 +2255,7 @@ public class Digester extends DefaultHandler2 {
* @see SetPropertiesRule
*/
public void addSetProperties(
- String pattern,
+ String pattern,
String attributeName,
String propertyName) {
@@ -2274,7 +2274,7 @@ public class Digester extends DefaultHandler2 {
* @see SetPropertiesRule
*/
public void addSetProperties(
- String pattern,
+ String pattern,
String [] attributeNames,
String [] propertyNames) {
@@ -2342,7 +2342,7 @@ public class Digester extends DefaultHandler2 {
* Clear the current contents of the object stack.
* <p>
* Calling this method <i>might</i> allow another document of the same type
- * to be correctly parsed. However this method was not intended for this
+ * to be correctly parsed. However this method was not intended for this
* purpose. In general, a separate Digester object should be created for
* each document to be parsed.
*/
@@ -2356,10 +2356,10 @@ public class Digester extends DefaultHandler2 {
log = null;
saxLog = null;
configured = false;
-
+
}
-
+
public void reset() {
root = null;
setErrorHandler(null);
@@ -2436,7 +2436,7 @@ public class Digester extends DefaultHandler2 {
/**
* Pushes the given object onto the stack with the given name.
* If no stack already exists with the given name then one will be created.
- *
+ *
* @param stackName the name of the stack onto which the object should be pushed
* @param value the Object to be pushed onto the named stack.
*
@@ -2456,9 +2456,9 @@ public class Digester extends DefaultHandler2 {
*
* <p><strong>Note:</strong> a stack is considered empty
* if no objects have been pushed onto it yet.</p>
- *
+ *
* @param stackName the name of the stack from which the top value is to be popped
- * @return the top <code>Object</code> on the stack or or null if the stack is either
+ * @return the top <code>Object</code> on the stack or or null if the stack is either
* empty or has not been created yet
* @throws EmptyStackException if the named stack is empty
*
@@ -2472,14 +2472,14 @@ public class Digester extends DefaultHandler2 {
log.debug("Stack '" + stackName + "' is empty");
}
throw new EmptyStackException();
-
+
} else {
-
+
result = namedStack.pop();
}
return result;
}
-
+
/**
* <p>Gets the top object from the stack with the given name.
* This method does not remove the object from the stack.
@@ -2488,9 +2488,9 @@ public class Digester extends DefaultHandler2 {
* if no objects have been pushed onto it yet.</p>
*
* @param stackName the name of the stack to be peeked
- * @return the top <code>Object</code> on the stack or null if the stack is either
+ * @return the top <code>Object</code> on the stack or null if the stack is either
* empty or has not been created yet
- * @throws EmptyStackException if the named stack is empty
+ * @throws EmptyStackException if the named stack is empty
*
* @since 1.6
*/
@@ -2500,11 +2500,11 @@ public class Digester extends DefaultHandler2 {
if (namedStack == null ) {
if (log.isDebugEnabled()) {
log.debug("Stack '" + stackName + "' is empty");
- }
+ }
throw new EmptyStackException();
-
+
} else {
-
+
result = namedStack.peek();
}
return result;
@@ -2514,9 +2514,9 @@ public class Digester extends DefaultHandler2 {
* <p>Is the stack with the given name empty?</p>
* <p><strong>Note:</strong> a stack is considered empty
* if no objects have been pushed onto it yet.</p>
- * @param stackName the name of the stack whose emptiness
+ * @param stackName the name of the stack whose emptiness
* should be evaluated
- * @return true if the given stack if empty
+ * @return true if the given stack if empty
*
* @since 1.6
*/
@@ -2528,19 +2528,19 @@ public class Digester extends DefaultHandler2 {
}
return result;
}
-
+
/**
- * When the Digester is being used as a SAXContentHandler,
+ * When the Digester is being used as a SAXContentHandler,
* this method allows you to access the root object that has been
* created after parsing.
- *
+ *
* @return the root object that has been created after parsing
* or null if the digester has not parsed any XML yet.
*/
public Object getRoot() {
return root;
}
-
+
// ------------------------------------------------ Parameter Stack Methods
@@ -2558,7 +2558,7 @@ public class Digester extends DefaultHandler2 {
* <p>
* <strong>Note</strong> This method may be called more than once.
* Once only initialization code should be placed in {@link #initialize}
- * or the code should take responsibility by checking and setting the
+ * or the code should take responsibility by checking and setting the
* {@link #configured} flag.
* </p>
*/
@@ -2580,19 +2580,19 @@ public class Digester extends DefaultHandler2 {
configured = true;
}
-
+
/**
* <p>
* Provides a hook for lazy initialization of this <code>Digester</code>
- * instance.
+ * instance.
* The default implementation does nothing, but subclasses
* can override as needed.
* Digester (by default) only calls this method once.
* </p>
*
* <p>
- * <strong>Note</strong> This method will be called by {@link #configure}
- * only when the {@link #configured} flag is false.
+ * <strong>Note</strong> This method will be called by {@link #configure}
+ * only when the {@link #configured} flag is false.
* Subclasses that override <code>configure</code> or who set <code>configured</code>
* may find that this method may be called more than once.
* </p>
@@ -2604,7 +2604,7 @@ public class Digester extends DefaultHandler2 {
// Perform lazy initialization as needed
// Nothing required by default
- }
+ }
// -------------------------------------------------------- Package Methods
@@ -2623,7 +2623,7 @@ public class Digester extends DefaultHandler2 {
* <p>Return the top object on the parameters stack without removing it. If there are
* no objects on the stack, return <code>null</code>.</p>
*
- * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters.
+ * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters.
* See {@link #params}.</p>
*/
public Object peekParams() {
@@ -2643,7 +2643,7 @@ public class Digester extends DefaultHandler2 {
* and [getCount()-1] is the bottom element. If the specified index
* is out of range, return <code>null</code>.</p>
*
- * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters.
+ * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters.
* See {@link #params}.</p>
*
* @param n Index of the desired element, where 0 is the top of the stack,
@@ -2665,7 +2665,7 @@ public class Digester extends DefaultHandler2 {
* <p>Pop the top object off of the parameters stack, and return it. If there are
* no objects on the stack, return <code>null</code>.</p>
*
- * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters.
+ * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters.
* See {@link #params}.</p>
*/
public Object popParams() {
@@ -2686,7 +2686,7 @@ public class Digester extends DefaultHandler2 {
/**
* <p>Push a new object onto the top of the parameters stack.</p>
*
- * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters.
+ * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters.
* See {@link #params}.</p>
*
* @param object The new object
@@ -2767,7 +2767,7 @@ public class Digester extends DefaultHandler2 {
public SAXException createSAXException(String message) {
return createSAXException(message, null);
}
-
+
// ------------------------------------------------------- Private Methods
@@ -2782,17 +2782,13 @@ public class Digester extends DefaultHandler2 {
if (list.getLength() == 0) {
return list;
}
-
+
AttributesImpl newAttrs = new AttributesImpl(list);
int nAttributes = newAttrs.getLength();
for (int i = 0; i < nAttributes; ++i) {
String value = newAttrs.getValue(i);
try {
- String newValue =
- IntrospectionUtils.replaceProperties(value, null, source);
- if (value != newValue) {
- newAttrs.setValue(i, newValue);
- }
+ newAttrs.setValue(i, IntrospectionUtils.replaceProperties(value, null, source).intern());
}
catch (Exception e) {
log.warn("Attribute [" + newAttrs.getLocalName(i) + "] failed to update and remains [" + value + "].", e);
@@ -2800,7 +2796,6 @@ public class Digester extends DefaultHandler2 {
}
return newAttrs;
-
}
diff --git a/java/org/apache/tomcat/util/modeler/ManagedBean.java b/java/org/apache/tomcat/util/modeler/ManagedBean.java
index 0f2e44c..93b68b4 100644
--- a/java/org/apache/tomcat/util/modeler/ManagedBean.java
+++ b/java/org/apache/tomcat/util/modeler/ManagedBean.java
@@ -5,9 +5,9 @@
* 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.
@@ -49,7 +49,7 @@ import javax.management.ServiceNotFoundException;
public class ManagedBean implements java.io.Serializable {
private static final long serialVersionUID = 1L;
-
+
private static final String BASE_MBEAN = "org.apache.tomcat.util.modeler.BaseModelMBean";
// ----------------------------------------------------- Instance Variables
static final Object[] NO_ARGS_PARAM = new Object[0];
@@ -69,7 +69,7 @@ public class ManagedBean implements java.io.Serializable {
private Map<String,OperationInfo> operations =
new HashMap<String,OperationInfo>();
-
+
protected String className = BASE_MBEAN;
//protected ConstructorInfo constructors[] = new ConstructorInfo[0];
protected String description = null;
@@ -81,9 +81,9 @@ public class ManagedBean implements java.io.Serializable {
protected NotificationInfo notifications[] = new NotificationInfo[0];
protected String type = null;
- /** Constructor. Will add default attributes.
- *
- */
+ /** Constructor. Will add default attributes.
+ *
+ */
public ManagedBean() {
AttributeInfo ai=new AttributeInfo();
ai.setName("modelerType");
@@ -92,7 +92,7 @@ public class ManagedBean implements java.io.Serializable {
ai.setWriteable(false);
addAttribute(ai);
}
-
+
// ------------------------------------------------------------- Properties
@@ -383,8 +383,8 @@ public class ManagedBean implements java.io.Serializable {
clazz = Class.forName(getClassName());
} catch (Exception e) {
}
-
- if( clazz==null ) {
+
+ if( clazz==null ) {
try {
ClassLoader cl= Thread.currentThread().getContextClassLoader();
if ( cl != null)
@@ -393,8 +393,8 @@ public class ManagedBean implements java.io.Serializable {
ex=e;
}
}
-
- if( clazz==null) {
+
+ if( clazz==null) {
throw new MBeanException
(ex, "Cannot load ModelMBean class " + getClassName());
}
@@ -409,9 +409,9 @@ public class ManagedBean implements java.io.Serializable {
getClassName());
}
}
-
+
mbean.setManagedBean(this);
-
+
// Set the managed resource (if any)
try {
if (instance != null)
@@ -471,11 +471,11 @@ public class ManagedBean implements java.io.Serializable {
// Construct and return a new ModelMBeanInfo object
- info = new MBeanInfo(getClassName(),
+ info = new MBeanInfo(getClassName(),
getDescription(),
- attributes,
- new MBeanConstructorInfo[] {},
- operations,
+ attributes,
+ new MBeanConstructorInfo[] {},
+ operations,
notifications);
// try {
// Descriptor descriptor = info.getMBeanDescriptor();
@@ -520,7 +520,7 @@ public class ManagedBean implements java.io.Serializable {
}
- Method getGetter(String aname, BaseModelMBean mbean, Object resource)
+ Method getGetter(String aname, BaseModelMBean mbean, Object resource)
throws AttributeNotFoundException, ReflectionException {
Method m = null;
@@ -529,7 +529,7 @@ public class ManagedBean implements java.io.Serializable {
// Look up the actual operation to be used
if (attrInfo == null)
throw new AttributeNotFoundException(" Cannot find attribute " + aname + " for " + resource);
-
+
String getMethod = attrInfo.getGetMethod();
if (getMethod == null)
throw new AttributeNotFoundException("Cannot find attribute " + aname + " get method name");
@@ -558,7 +558,7 @@ public class ManagedBean implements java.io.Serializable {
return m;
}
- public Method getSetter(String aname, BaseModelMBean bean, Object resource)
+ public Method getSetter(String aname, BaseModelMBean bean, Object resource)
throws AttributeNotFoundException, ReflectionException {
Method m = null;
@@ -602,11 +602,11 @@ public class ManagedBean implements java.io.Serializable {
return m;
}
- public Method getInvoke(String aname, Object[] params, String[] signature, BaseModelMBean bean, Object resource)
+ public Method getInvoke(String aname, Object[] params, String[] signature, BaseModelMBean bean, Object resource)
throws MBeanException, ReflectionException {
Method method = null;
-
+
if (params == null)
params = new Object[0];
if (signature == null)
@@ -671,7 +671,7 @@ public class ManagedBean implements java.io.Serializable {
}
key.append(')');
- return key.toString();
+ return key.toString().intern();
}
@@ -686,6 +686,6 @@ public class ManagedBean implements java.io.Serializable {
}
key.append(')');
- return key.toString();
+ return key.toString().intern();
}
}
diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java
index c90a7a5..fa5c4d8 100644
--- a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java
+++ b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java
@@ -356,8 +356,8 @@ public class MbeansDescriptorsIntrospectionSource extends ModelerSource
for(int i=0; i<parms.length; i++ ) {
ParameterInfo pi=new ParameterInfo();
pi.setType(parms[i].getName());
- pi.setName( "param" + i);
- pi.setDescription("Introspected parameter param" + i);
+ pi.setName(("param" + i).intern());
+ pi.setDescription(("Introspected parameter param" + i).intern());
op.addParameter(pi);
}
mbean.addOperation(op);
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 438bc5e..f6d55d8 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -73,6 +73,13 @@
searching for nested groups when the JNDIRealm is configured with
<code>roleNested</code> set to <code>true</code>. (markt)
</fix>
+ <fix>
+ <bug>63236</bug>: Use <code>String.intern()</code> as suggested by
+ Phillip Webb to reduce memory wasted due to String duplication. This
+ changes saves ~245k when starting a clean installation. With additional
+ thanks to YourKit Java profiler for helping to track down the wasted
+ memory and the root causes. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Coyote">
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org