You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2020/06/23 11:41:51 UTC

[tomcat] 03/05: Do the code generation tooling for context.xml files

This is an automated email from the ASF dual-hosted git repository.

remm pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 1d10b19c7ced08d6f81e8c93a67d321a1307c47f
Author: remm <re...@apache.org>
AuthorDate: Mon Jun 22 17:20:24 2020 +0200

    Do the code generation tooling for context.xml files
    
    Drop the hack that used the hash code to create variable names since it
    does not work, instead a list of objects used had to be kept. The names
    are more readable so it's not a bad move anyway.
    Using the generated code (beyond looking for a Tomcat embedded example)
    during load will be done only when using an explicit flag.
    I will document this tooling.
    Most likely some additional escaping and fixes are needed.
---
 java/org/apache/catalina/startup/Catalina.java     |  84 +++++---
 .../org/apache/catalina/startup/ContextConfig.java | 231 +++++++++++++++++++--
 .../catalina/startup/ListenerCreateRule.java       |  12 +-
 .../apache/catalina/startup/SetNextNamingRule.java |  12 +-
 .../org/apache/tomcat/util/IntrospectionUtils.java |  31 ++-
 .../tomcat/util/descriptor/web/ContextEjb.java     |   5 -
 .../util/descriptor/web/ContextEnvironment.java    |   3 -
 .../tomcat/util/descriptor/web/ContextHandler.java |   4 -
 .../util/descriptor/web/ContextLocalEjb.java       |   4 -
 .../util/descriptor/web/ContextResource.java       |   4 -
 .../util/descriptor/web/ContextResourceEnvRef.java |   4 -
 .../util/descriptor/web/ContextResourceLink.java   |   4 -
 .../tomcat/util/descriptor/web/ContextService.java |   4 -
 .../util/descriptor/web/MessageDestination.java    |   4 -
 .../util/descriptor/web/MessageDestinationRef.java |   4 -
 .../tomcat/util/descriptor/web/ResourceBase.java   |  10 -
 .../tomcat/util/digester/CallMethodRule.java       |   6 +-
 java/org/apache/tomcat/util/digester/Digester.java |  30 ++-
 18 files changed, 346 insertions(+), 110 deletions(-)

diff --git a/java/org/apache/catalina/startup/Catalina.java b/java/org/apache/catalina/startup/Catalina.java
index b03d4ce..5e6bb12 100644
--- a/java/org/apache/catalina/startup/Catalina.java
+++ b/java/org/apache/catalina/startup/Catalina.java
@@ -135,11 +135,17 @@ public class Catalina {
 
 
     /**
-     * Generate Tomcat embedded code from server.xml.
+     * Generate Tomcat embedded code from configuration files.
      */
     protected boolean generateCode = false;
 
 
+    /**
+     * Use generated code as a replacement for configuration files.
+     */
+    protected boolean useGeneratedCode = false;
+
+
     // ----------------------------------------------------------- Constructors
 
     public Catalina() {
@@ -170,6 +176,26 @@ public class Catalina {
     }
 
 
+    public boolean getGenerateCode() {
+        return this.generateCode;
+    }
+
+
+    public void setGenerateCode(boolean generateCode) {
+        this.generateCode = generateCode;
+    }
+
+
+    public boolean getUseGeneratedCode() {
+        return this.useGeneratedCode;
+    }
+
+
+    public void setUseGeneratedCode(boolean useGeneratedCode) {
+        this.useGeneratedCode = useGeneratedCode;
+    }
+
+
     /**
      * Set the shared extensions class loader.
      *
@@ -247,6 +273,8 @@ public class Catalina {
                 isConfig = true;
             } else if (arg.equals("-generateCode")) {
                 generateCode = true;
+            } else if (arg.equals("-useGeneratedCode")) {
+                useGeneratedCode = true;
             } else if (arg.equals("-nonaming")) {
                 setUseNaming(false);
             } else if (arg.equals("-help")) {
@@ -558,50 +586,49 @@ public class Catalina {
         ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
         File file = configFile();
 
-        try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
-            String serverXmlId = String.valueOf(resource.getLastModified());
-            String serverXmlClassName = "catalina.ServerXml_" + serverXmlId;
-            ServerXml serverXml = null;
+        ServerXml serverXml = null;
+        if (useGeneratedCode) {
+            String xmlClassName = "catalina.ServerXml";
             try {
-                serverXml = (ServerXml) Catalina.class.getClassLoader().loadClass(serverXmlClassName).newInstance();
-            } catch (ClassNotFoundException e) {
+                serverXml = (ServerXml) Catalina.class.getClassLoader().loadClass(xmlClassName).newInstance();
+            } catch (Exception e) {
                 // Ignore, no generated code found
             }
-            if (serverXml != null) {
-                serverXml.load(this);
-            } else {
+        }
+
+        if (serverXml != null) {
+            serverXml.load(this);
+        } else {
+            try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
                 // Create and execute our Digester
                 Digester digester = createStartDigester();
-
                 InputStream inputStream = resource.getInputStream();
                 InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
                 inputSource.setByteStream(inputStream);
                 digester.push(this);
                 if (generateCode) {
                     digester.startGeneratingCode();
-                    generateClassHeader(digester, String.valueOf(resource.getLastModified()));
+                    generateClassHeader(digester);
                 }
                 digester.parse(inputSource);
                 if (generateCode) {
                     generateClassFooter(digester);
                     File generatedSourceFolder = new File(new File(Bootstrap.getCatalinaHomeFile(), "work"), "catalina");
                     if (generatedSourceFolder.isDirectory() || generatedSourceFolder.mkdirs()) {
-                        File generatedSourceFile = new File(generatedSourceFolder,
-                                "ServerXml_" + serverXmlId + ".java");
-                        if (!generatedSourceFile.exists()) {
-                            try (FileWriter writer = new FileWriter(generatedSourceFile)) {
-                                writer.write(digester.getGeneratedCode().toString());
-                            }
+                        File generatedSourceFile = new File(generatedSourceFolder, "ServerXml.java");
+                        try (FileWriter writer = new FileWriter(generatedSourceFile)) {
+                            writer.write(digester.getGeneratedCode().toString());
                         }
                     }
+                    digester.endGeneratingCode();
                 }
+            } catch (Exception e) {
+                log.warn(sm.getString("catalina.configFail", file.getAbsolutePath()), e);
+                if (file.exists() && !file.canRead()) {
+                    log.warn(sm.getString("catalina.incorrectPermissions"));
+                }
+                return;
             }
-        } catch (Exception e) {
-            log.warn(sm.getString("catalina.configFail", file.getAbsolutePath()), e);
-            if (file.exists() && !file.canRead()) {
-                log.warn(sm.getString("catalina.incorrectPermissions"));
-            }
-            return;
         }
 
         getServer().setCatalina(this);
@@ -672,9 +699,8 @@ public class Catalina {
             return;
         }
 
-        long t2 = System.nanoTime();
-        if(log.isInfoEnabled()) {
-            log.info(sm.getString("catalina.startup", Long.valueOf((t2 - t1) / 1000000)));
+        if (log.isInfoEnabled()) {
+            log.info(sm.getString("catalina.startup", TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t1)));
         }
 
         // Register shutdown hook
@@ -819,10 +845,10 @@ public class Catalina {
     }
 
 
-    protected void generateClassHeader(Digester digester, String time) {
+    protected void generateClassHeader(Digester digester) {
         StringBuilder code = digester.getGeneratedCode();
         code.append("package catalina;").append(System.lineSeparator());
-        code.append("public class ServerXml_").append(time).append(" implements ");
+        code.append("public class ServerXml implements ");
         code.append(ServerXml.class.getName().replace('$', '.')).append(" {").append(System.lineSeparator());
         code.append("public void load(").append(Catalina.class.getName());
         code.append(" ").append(digester.toVariableName(this)).append(") {").append(System.lineSeparator());
diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java
index 2c09a15..1d4c0e2 100644
--- a/java/org/apache/catalina/startup/ContextConfig.java
+++ b/java/org/apache/catalina/startup/ContextConfig.java
@@ -19,6 +19,7 @@ package org.apache.catalina.startup;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
@@ -442,6 +443,98 @@ public class ContextConfig implements LifecycleListener {
     }
 
 
+    protected boolean getGenerateCode() {
+        Catalina catalina = Container.getService(context).getServer().getCatalina();
+        if (catalina != null) {
+            return catalina.getGenerateCode();
+        } else {
+            return false;
+        }
+    }
+
+
+    protected boolean getUseGeneratedCode() {
+        Catalina catalina = Container.getService(context).getServer().getCatalina();
+        if (catalina != null) {
+            return catalina.getUseGeneratedCode();
+        } else {
+            return false;
+        }
+    }
+
+
+    protected static String getContextXmlPackageName(Container container) {
+        StringBuffer result = new StringBuffer();
+        Container host = null;
+        Container engine = null;
+        while (container != null) {
+            if (container instanceof Host) {
+                host = container;
+            } else if (container instanceof Engine) {
+                engine = container;
+            }
+            container = container.getParent();
+        }
+        result.append("catalina");
+        if (engine != null) {
+            result.append('.');
+        }
+        if (engine != null) {
+            result.append(engine.getName());
+            if (host != null) {
+                result.append('.');
+            }
+        }
+        if (host != null) {
+            result.append(host.getName());
+        }
+        return result.toString();
+    }
+
+
+    protected static File getContextXmlJavaSource(String contextXmlPackageName, String contextXmlSimpleClassName) {
+        File generatedSourceFolder = new File(Bootstrap.getCatalinaHomeFile(), "work");
+        if (generatedSourceFolder.isDirectory() || generatedSourceFolder.mkdirs()) {
+            String path = contextXmlPackageName.replace('.', File.separatorChar);
+            File packageFolder = new File(generatedSourceFolder, path);
+            if (packageFolder.isDirectory() || packageFolder.mkdirs()) {
+                return new File(packageFolder, contextXmlSimpleClassName + ".java");
+            }
+        }
+        return null;
+    }
+
+
+    protected void generateClassHeader(Digester digester, String packageName, String resourceName) {
+        StringBuilder code = digester.getGeneratedCode();
+        code.append("package ").append(packageName).append(";").append(System.lineSeparator());
+        code.append("public class ").append(resourceName).append(" implements ");
+        code.append(ContextXml.class.getName().replace('$', '.'));
+        code.append(" {").append(System.lineSeparator());
+        code.append("public void load(");
+        code.append(Context.class.getName());
+        String contextArgument = digester.toVariableName(context);
+        code.append(" ").append(contextArgument).append(") {").append(System.lineSeparator());
+        // Create a new variable with the concrete type
+        digester.setKnown(context);
+        code.append(context.getClass().getName()).append(" ").append(digester.toVariableName(context));
+        code.append(" = (").append(context.getClass().getName()).append(") ").append(contextArgument);
+        code.append(";").append(System.lineSeparator());
+    }
+
+
+    protected void generateClassFooter(Digester digester) {
+        StringBuilder code = digester.getGeneratedCode();
+        code.append("}").append(System.lineSeparator());
+        code.append("}").append(System.lineSeparator());
+    }
+
+
+    public interface ContextXml {
+        public void load(Context context);
+    }
+
+
     /**
      * Process the default configuration file, if it exists.
      * @param digester The digester that will be used for XML parsing
@@ -450,6 +543,14 @@ public class ContextConfig implements LifecycleListener {
 
         String defaultContextXml = null;
 
+        boolean generateCode = getGenerateCode();
+        boolean useGeneratedCode = getUseGeneratedCode();
+
+        String contextXmlPackageName = null;
+        String contextXmlSimpleClassName = null;
+        String contextXmlClassName = null;
+        File contextXmlJavaSource = null;
+
         // Open the default context.xml file, if it exists
         if (context instanceof StandardContext) {
             defaultContextXml = ((StandardContext)context).getDefaultContextXml();
@@ -459,30 +560,123 @@ public class ContextConfig implements LifecycleListener {
             defaultContextXml = Constants.DefaultContextXml;
         }
 
+        ContextXml contextXml = null;
+
         if (!context.getOverride()) {
-            try (ConfigurationSource.Resource contextXmlResource =
-                    ConfigFileLoader.getSource().getResource(defaultContextXml)) {
-                URL defaultContextUrl = contextXmlResource.getURI().toURL();
-                processContextConfig(digester, defaultContextUrl, contextXmlResource.getInputStream());
-            } catch (MalformedURLException e) {
-                log.error(sm.getString("contextConfig.badUrl", defaultContextXml), e);
-            } catch (IOException e) {
-                // Not found
+
+            if (useGeneratedCode || generateCode) {
+                contextXmlPackageName = "catalina";
+                contextXmlSimpleClassName = "ContextXmlDefault";
+                contextXmlClassName = contextXmlPackageName + "." + contextXmlSimpleClassName;
+            }
+            if (useGeneratedCode) {
+                try {
+                    contextXml = (ContextXml) Catalina.class.getClassLoader().loadClass(contextXmlClassName).newInstance();
+                } catch (Exception e) {
+                    // Ignore, no generated code found
+                }
+            }
+            if (contextXml != null) {
+                contextXml.load(context);
+                contextXml = null;
+            } else {
+                try (ConfigurationSource.Resource contextXmlResource =
+                        ConfigFileLoader.getSource().getResource(defaultContextXml)) {
+                    if (generateCode) {
+                        contextXmlJavaSource = getContextXmlJavaSource(contextXmlPackageName, contextXmlSimpleClassName);
+                        digester.startGeneratingCode();
+                        generateClassHeader(digester, contextXmlPackageName, contextXmlSimpleClassName);
+                    }
+                    URL defaultContextUrl = contextXmlResource.getURI().toURL();
+                    processContextConfig(digester, defaultContextUrl, contextXmlResource.getInputStream());
+                    if (generateCode) {
+                        generateClassFooter(digester);
+                        try (FileWriter writer = new FileWriter(contextXmlJavaSource)) {
+                            writer.write(digester.getGeneratedCode().toString());
+                        }
+                        digester.endGeneratingCode();
+                    }
+                } catch (MalformedURLException e) {
+                    log.error(sm.getString("contextConfig.badUrl", defaultContextXml), e);
+                } catch (IOException e) {
+                    // Not found
+                }
             }
 
-            String hostContextFile = Container.getConfigPath(context, Constants.HostContextXml);
-            try (ConfigurationSource.Resource contextXmlResource =
-                    ConfigFileLoader.getSource().getResource(hostContextFile)) {
-                URL defaultContextUrl = contextXmlResource.getURI().toURL();
-                processContextConfig(digester, defaultContextUrl, contextXmlResource.getInputStream());
-            } catch (MalformedURLException e) {
-                log.error(sm.getString("contextConfig.badUrl", hostContextFile), e);
-            } catch (IOException e) {
-                // Not found
+            if (useGeneratedCode || generateCode) {
+                contextXmlPackageName = getContextXmlPackageName(context);
+                contextXmlSimpleClassName = "ContextXmlDefault";
+                contextXmlClassName = contextXmlPackageName + "." + contextXmlSimpleClassName;
+            }
+            if (useGeneratedCode) {
+                try {
+                    contextXml = (ContextXml) Catalina.class.getClassLoader().loadClass(contextXmlClassName).newInstance();
+                } catch (Exception e) {
+                    // Ignore, no generated code found
+                }
+            }
+            if (contextXml != null) {
+                contextXml.load(context);
+                contextXml = null;
+            } else {
+                String hostContextFile = Container.getConfigPath(context, Constants.HostContextXml);
+                try (ConfigurationSource.Resource contextXmlResource =
+                        ConfigFileLoader.getSource().getResource(hostContextFile)) {
+                    if (generateCode) {
+                        contextXmlJavaSource = getContextXmlJavaSource(contextXmlPackageName, contextXmlSimpleClassName);
+                        digester.startGeneratingCode();
+                        generateClassHeader(digester, contextXmlPackageName, contextXmlSimpleClassName);
+                    }
+                    URL defaultContextUrl = contextXmlResource.getURI().toURL();
+                    processContextConfig(digester, defaultContextUrl, contextXmlResource.getInputStream());
+                    if (generateCode) {
+                        generateClassFooter(digester);
+                        try (FileWriter writer = new FileWriter(contextXmlJavaSource)) {
+                            writer.write(digester.getGeneratedCode().toString());
+                        }
+                        digester.endGeneratingCode();
+                    }
+                } catch (MalformedURLException e) {
+                    log.error(sm.getString("contextConfig.badUrl", hostContextFile), e);
+                } catch (IOException e) {
+                    // Not found
+                }
             }
         }
+
         if (context.getConfigFile() != null) {
-            processContextConfig(digester, context.getConfigFile(), null);
+            if (useGeneratedCode || generateCode) {
+                contextXmlPackageName = getContextXmlPackageName(context);
+                contextXmlSimpleClassName = "ContextXml_" + context.getName().replace('/', '_').replace("-", "__");
+                contextXmlClassName = contextXmlPackageName + "." + contextXmlSimpleClassName;
+            }
+            if (useGeneratedCode) {
+                try {
+                    contextXml = (ContextXml) Catalina.class.getClassLoader().loadClass(contextXmlClassName).newInstance();
+                } catch (Exception e) {
+                    // Ignore, no generated code found
+                }
+            }
+            if (contextXml != null) {
+                contextXml.load(context);
+                contextXml = null;
+            } else {
+                if (generateCode) {
+                    contextXmlJavaSource = getContextXmlJavaSource(contextXmlPackageName, contextXmlSimpleClassName);
+                    digester.startGeneratingCode();
+                    generateClassHeader(digester, contextXmlPackageName, contextXmlSimpleClassName);
+                }
+                processContextConfig(digester, context.getConfigFile(), null);
+                if (generateCode) {
+                    generateClassFooter(digester);
+                    try (FileWriter writer = new FileWriter(contextXmlJavaSource)) {
+                        writer.write(digester.getGeneratedCode().toString());
+                    } catch (IOException e) {
+                        // Ignore
+                    }
+                    digester.endGeneratingCode();
+                }
+            }
         }
 
     }
@@ -728,6 +922,7 @@ public class ContextConfig implements LifecycleListener {
     protected synchronized void init() {
         // Called from StandardContext.init()
 
+        // FIXME: Try to avoid creation of the parser if not needed due to code generation
         Digester contextDigester = createContextDigester();
         contextDigester.getParser();
 
diff --git a/java/org/apache/catalina/startup/ListenerCreateRule.java b/java/org/apache/catalina/startup/ListenerCreateRule.java
index 4a63952..9f1d5e1 100644
--- a/java/org/apache/catalina/startup/ListenerCreateRule.java
+++ b/java/org/apache/catalina/startup/ListenerCreateRule.java
@@ -56,14 +56,22 @@ public class ListenerCreateRule extends ObjectCreateRule {
                 } else {
                     log.info(sm.getString("listener.createFailed", className));
                 }
-                digester.push(new OptionalListener(className));
+                Object instance = new OptionalListener(className);
+                digester.push(instance);
+                StringBuilder code = digester.getGeneratedCode();
+                if (code != null) {
+                    code.append(OptionalListener.class.getName().replace('$', '.')).append(" ");
+                    code.append(digester.toVariableName(instance)).append(" = new ");
+                    code.append(OptionalListener.class.getName().replace('$', '.')).append("(\"").append(className).append("\");");
+                    code.append(System.lineSeparator());
+                }
             }
         } else {
             super.begin(namespace, name, attributes);
         }
     }
 
-    public class OptionalListener implements LifecycleListener {
+    public static class OptionalListener implements LifecycleListener {
         protected final String className;
         protected final HashMap<String, String> properties = new HashMap<>();
         public OptionalListener(String className) {
diff --git a/java/org/apache/catalina/startup/SetNextNamingRule.java b/java/org/apache/catalina/startup/SetNextNamingRule.java
index cf94b7c..20d7e3c 100644
--- a/java/org/apache/catalina/startup/SetNextNamingRule.java
+++ b/java/org/apache/catalina/startup/SetNextNamingRule.java
@@ -21,7 +21,6 @@ package org.apache.catalina.startup;
 import org.apache.catalina.Context;
 import org.apache.catalina.deploy.NamingResourcesImpl;
 import org.apache.tomcat.util.IntrospectionUtils;
-import org.apache.tomcat.util.descriptor.web.ResourceBase;
 import org.apache.tomcat.util.digester.Rule;
 
 
@@ -93,10 +92,12 @@ public class SetNextNamingRule extends Rule {
         // Identify the objects to be used
         Object child = digester.peek(0);
         Object parent = digester.peek(1);
+        boolean context = false;
 
         NamingResourcesImpl namingResources = null;
         if (parent instanceof Context) {
             namingResources = ((Context) parent).getNamingResources();
+            context = true;
         } else {
             namingResources = (NamingResourcesImpl) parent;
         }
@@ -107,8 +108,13 @@ public class SetNextNamingRule extends Rule {
 
         StringBuilder code = digester.getGeneratedCode();
         if (code != null) {
-            code.append(digester.toVariableName(namingResources)).append(".").append(methodName).append("(");
-            code.append(digester.toVariableName(child, ((ResourceBase) child).getInitialHashCode())).append(");");
+            if (context) {
+                code.append(digester.toVariableName(parent)).append(".getNamingResources()");
+            } else {
+                code.append(digester.toVariableName(namingResources));
+            }
+            code.append(".").append(methodName).append("(");
+            code.append(digester.toVariableName(child)).append(");");
             code.append(System.lineSeparator());
         }
     }
diff --git a/java/org/apache/tomcat/util/IntrospectionUtils.java b/java/org/apache/tomcat/util/IntrospectionUtils.java
index 4355882..1d830e1 100644
--- a/java/org/apache/tomcat/util/IntrospectionUtils.java
+++ b/java/org/apache/tomcat/util/IntrospectionUtils.java
@@ -74,7 +74,7 @@ public final class IntrospectionUtils {
                         && "java.lang.String".equals(paramT[0].getName())) {
                     item.invoke(o, new Object[]{value});
                     if (actualMethod != null) {
-                        actualMethod.append(item.getName()).append("(\"").append(value).append("\")");
+                        actualMethod.append(item.getName()).append("(\"").append(escape(value)).append("\")");
                     }
                     return true;
                 }
@@ -160,7 +160,7 @@ public final class IntrospectionUtils {
             if (invokeSetProperty && (setPropertyMethodBool != null ||
                     setPropertyMethodVoid != null)) {
                 if (actualMethod != null) {
-                    actualMethod.append("setProperty(\"").append(name).append("\", \"").append(value).append("\")");
+                    actualMethod.append("setProperty(\"").append(name).append("\", \"").append(escape(value)).append("\")");
                 }
                 Object params[] = new Object[2];
                 params[0] = name;
@@ -194,6 +194,33 @@ public final class IntrospectionUtils {
         return false;
     }
 
+    /**
+     * @param s
+     *            the input string
+     * @return escaped string, per Java rule
+     */
+    public static String escape(String s) {
+
+        if (s == null)
+            return "";
+
+        StringBuilder b = new StringBuilder();
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '"')
+                b.append('\\').append('"');
+            else if (c == '\\')
+                b.append('\\').append('\\');
+            else if (c == '\n')
+                b.append('\\').append('n');
+            else if (c == '\r')
+                b.append('\\').append('r');
+            else
+                b.append(c);
+        }
+        return b.toString();
+    }
+
     public static Object getProperty(Object o, String name) {
         String getter = "get" + capitalize(name);
         String isGetter = "is" + capitalize(name);
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextEjb.java b/java/org/apache/tomcat/util/descriptor/web/ContextEjb.java
index 8e2b177..a650afe 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextEjb.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextEjb.java
@@ -30,14 +30,9 @@ public class ContextEjb extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public ContextEjb() {
-        initialHashCode = hashCode();
-    }
-
     // ------------------------------------------------------------- Properties
 
 
-
     /**
      * The name of the EJB home implementation class.
      */
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextEnvironment.java b/java/org/apache/tomcat/util/descriptor/web/ContextEnvironment.java
index b606961..43d110c 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextEnvironment.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextEnvironment.java
@@ -28,9 +28,6 @@ public class ContextEnvironment extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public ContextEnvironment() {
-        initialHashCode = hashCode();
-    }
 
     // ------------------------------------------------------------- Properties
 
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextHandler.java b/java/org/apache/tomcat/util/descriptor/web/ContextHandler.java
index 7b124aa..c0ee25c 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextHandler.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextHandler.java
@@ -34,10 +34,6 @@ public class ContextHandler extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public ContextHandler() {
-        initialHashCode = hashCode();
-    }
-
     // ------------------------------------------------------------- Properties
 
 
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextLocalEjb.java b/java/org/apache/tomcat/util/descriptor/web/ContextLocalEjb.java
index ecfc1e3..29e8d5e 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextLocalEjb.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextLocalEjb.java
@@ -30,10 +30,6 @@ public class ContextLocalEjb extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public ContextLocalEjb() {
-        initialHashCode = hashCode();
-    }
-
     // ------------------------------------------------------------- Properties
 
     /**
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextResource.java b/java/org/apache/tomcat/util/descriptor/web/ContextResource.java
index b4115bd..dd3de30 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextResource.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextResource.java
@@ -30,10 +30,6 @@ public class ContextResource extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public ContextResource() {
-        initialHashCode = hashCode();
-    }
-
     // ------------------------------------------------------------- Properties
 
 
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextResourceEnvRef.java b/java/org/apache/tomcat/util/descriptor/web/ContextResourceEnvRef.java
index 81b6aa6..ba3169c 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextResourceEnvRef.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextResourceEnvRef.java
@@ -29,10 +29,6 @@ public class ContextResourceEnvRef extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public ContextResourceEnvRef() {
-        initialHashCode = hashCode();
-    }
-
     // ------------------------------------------------------------- Properties
 
     /**
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextResourceLink.java b/java/org/apache/tomcat/util/descriptor/web/ContextResourceLink.java
index 6b88c07..e50dcf9 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextResourceLink.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextResourceLink.java
@@ -30,10 +30,6 @@ public class ContextResourceLink extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public ContextResourceLink() {
-        initialHashCode = hashCode();
-    }
-
     // ------------------------------------------------------------- Properties
 
    /**
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextService.java b/java/org/apache/tomcat/util/descriptor/web/ContextService.java
index a8e2331..cefdc56 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextService.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextService.java
@@ -33,10 +33,6 @@ public class ContextService extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public ContextService() {
-        initialHashCode = hashCode();
-    }
-
     // ------------------------------------------------------------- Properties
 
 
diff --git a/java/org/apache/tomcat/util/descriptor/web/MessageDestination.java b/java/org/apache/tomcat/util/descriptor/web/MessageDestination.java
index b4a97f2..be9fcfb 100644
--- a/java/org/apache/tomcat/util/descriptor/web/MessageDestination.java
+++ b/java/org/apache/tomcat/util/descriptor/web/MessageDestination.java
@@ -29,10 +29,6 @@ public class MessageDestination extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public MessageDestination() {
-        initialHashCode = hashCode();
-    }
-
     // ------------------------------------------------------------- Properties
 
 
diff --git a/java/org/apache/tomcat/util/descriptor/web/MessageDestinationRef.java b/java/org/apache/tomcat/util/descriptor/web/MessageDestinationRef.java
index be8b44f..25d9f67 100644
--- a/java/org/apache/tomcat/util/descriptor/web/MessageDestinationRef.java
+++ b/java/org/apache/tomcat/util/descriptor/web/MessageDestinationRef.java
@@ -29,10 +29,6 @@ public class MessageDestinationRef extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
-    public MessageDestinationRef() {
-        initialHashCode = hashCode();
-    }
-
     // ------------------------------------------------------------- Properties
 
 
diff --git a/java/org/apache/tomcat/util/descriptor/web/ResourceBase.java b/java/org/apache/tomcat/util/descriptor/web/ResourceBase.java
index e191b46..37ec8fb 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ResourceBase.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ResourceBase.java
@@ -96,16 +96,6 @@ public class ResourceBase implements Serializable, Injectable {
 
 
     /**
-     * Store the initial hash code of the object, as the override
-     * can mess some operations.
-     */
-    protected int initialHashCode = 0;
-
-    public int getInitialHashCode() {
-        return initialHashCode;
-    }
-
-    /**
      * Holder for our configured properties.
      */
     private final Map<String, Object> properties = new HashMap<>();
diff --git a/java/org/apache/tomcat/util/digester/CallMethodRule.java b/java/org/apache/tomcat/util/digester/CallMethodRule.java
index 0d8c468..83aaf57 100644
--- a/java/org/apache/tomcat/util/digester/CallMethodRule.java
+++ b/java/org/apache/tomcat/util/digester/CallMethodRule.java
@@ -392,7 +392,11 @@ public class CallMethodRule extends Rule {
                 if (i > 0) {
                     code.append(",");
                 }
-                code.append(digester.toVariableName(paramValues[i]));
+                if (bodyText != null) {
+                    code.append("\"").append(bodyText).append("\"");
+                } else {
+                    code.append(digester.toVariableName(paramValues[i]));
+                }
             }
             code.append(");");
             code.append(System.lineSeparator());
diff --git a/java/org/apache/tomcat/util/digester/Digester.java b/java/org/apache/tomcat/util/digester/Digester.java
index 9ef59a4..7153b52 100644
--- a/java/org/apache/tomcat/util/digester/Digester.java
+++ b/java/org/apache/tomcat/util/digester/Digester.java
@@ -394,16 +394,36 @@ public class Digester extends DefaultHandler2 {
         code = new StringBuilder();
     }
 
+    public void endGeneratingCode() {
+        code = null;
+        known.clear();
+    }
+
     public StringBuilder getGeneratedCode() {
         return code;
     }
 
-    public String toVariableName(Object object) {
-        return toVariableName(object, object.hashCode());
+    protected ArrayList<Object> known = new ArrayList<>();
+    public void setKnown(Object object) {
+        known.add(object);
     }
-
-    public String toVariableName(Object object, int hashCode) {
-        return "tc_" + object.getClass().getSimpleName() + "_" + String.valueOf(Math.abs(hashCode));
+    public String toVariableName(Object object) {
+        boolean found = false;
+        int pos = 0;
+        if (known.size() > 0) {
+            for (int i = known.size() - 1; i >= 0; i--) {
+                if (known.get(i) == object) {
+                    pos = i;
+                    found = true;
+                    break;
+                }
+            }
+        }
+        if (!found) {
+            pos = known.size();
+            known.add(object);
+        }
+        return "tc_" + object.getClass().getSimpleName() + "_" + String.valueOf(pos);
     }
 
     // ------------------------------------------------------------- Properties


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org