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 55ef30d459f859d92a562eed9bd1b7d080a510b4
Author: remm <r...@apache.org>
AuthorDate: Thu Jun 18 15:07:39 2020 +0200

    Add a code generator for server.xml by taking advantage of the digester
    
    This produces a Tomcat embedded out of server.xml. Only the rules used
    by server.xml have code generation at the moment. The code is generated
    in the work directory.
    Also minor refactorings and simplifications, like for the properties
    related rules which could use the main one.
    For some reason, it is only marginally faster than actually using the
    digester and regular XML parsing. I expected better results overall and
    it could be useful to investigate.
    However this still has benefits:
    - It is better for AOT compilation; I will likely be moving the Tomcat
    standalone "blueprint" for AOT compilation use from res/tomcat-maven to
    a new module since this will eventually expand to include all the extra
    steps that can benefit AOT
    - It can be educational about how to use the Tomcat embedded API
    - People using Tomcat embedded could use it to generate code for complex
    configurations, and this guarantees server.xml equivalence
    - Maybe there will be benefits if the technique is applied to the larger
    and more numerous web.xml files (but it is possible other methods are
    better there, I will investigate)
---
 .../apache/catalina/startup/AddPortOffsetRule.java |   7 +
 java/org/apache/catalina/startup/Catalina.java     | 144 +++++++++++++++------
 .../catalina/startup/CertificateCreateRule.java    |  11 +-
 .../catalina/startup/ConnectorCreateRule.java      |  31 ++++-
 .../apache/catalina/startup/ContextRuleSet.java    |   2 +-
 .../startup/CopyParentClassLoaderRule.java         |   6 +
 .../catalina/startup/LifecycleListenerRule.java    |   6 +
 .../org/apache/catalina/startup/NamingRuleSet.java |  12 +-
 .../catalina/startup/SetAllPropertiesRule.java     |  52 +-------
 .../catalina/startup/SetContextPropertiesRule.java |  42 +-----
 .../apache/catalina/startup/SetNextNamingRule.java |   7 +
 .../org/apache/tomcat/util/IntrospectionUtils.java |  31 ++++-
 .../tomcat/util/descriptor/web/ContextEjb.java     |   4 +
 .../util/descriptor/web/ContextEnvironment.java    |   4 +
 .../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       |  14 ++
 java/org/apache/tomcat/util/digester/Digester.java |  27 ++++
 .../tomcat/util/digester/ObjectCreateRule.java     |  10 ++
 .../apache/tomcat/util/digester/SetNextRule.java   |   6 +
 .../tomcat/util/digester/SetPropertiesRule.java    |  48 ++++++-
 28 files changed, 362 insertions(+), 144 deletions(-)

diff --git a/java/org/apache/catalina/startup/AddPortOffsetRule.java 
b/java/org/apache/catalina/startup/AddPortOffsetRule.java
index 9b961cb..50f3fc0 100644
--- a/java/org/apache/catalina/startup/AddPortOffsetRule.java
+++ b/java/org/apache/catalina/startup/AddPortOffsetRule.java
@@ -32,5 +32,12 @@ public class AddPortOffsetRule extends Rule {
 
         int portOffset = server.getPortOffset();
         conn.setPortOffset(portOffset);
+
+        StringBuilder code = digester.getGeneratedCode();
+        if (code != null) {
+            
code.append(digester.toVariableName(conn)).append(".setPortOffset(");
+            
code.append(digester.toVariableName(server)).append(".getPortOffset());");
+            code.append(System.lineSeparator());
+        }
     }
 }
\ No newline at end of file
diff --git a/java/org/apache/catalina/startup/Catalina.java 
b/java/org/apache/catalina/startup/Catalina.java
index 00c820e..ecf197f 100644
--- a/java/org/apache/catalina/startup/Catalina.java
+++ b/java/org/apache/catalina/startup/Catalina.java
@@ -19,6 +19,7 @@ package org.apache.catalina.startup;
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -29,6 +30,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.logging.LogManager;
 
 import org.apache.catalina.Container;
@@ -132,6 +134,19 @@ public class Catalina {
     protected boolean loaded = false;
 
 
+    /**
+     * Rethrow exceptions on init failure.
+     */
+    protected boolean throwOnInitFailure =
+            
Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE");
+
+
+    /**
+     * Generate Tomcat embedded code from server.xml.
+     */
+    protected boolean generateCode = false;
+
+
     // ----------------------------------------------------------- Constructors
 
     public Catalina() {
@@ -237,6 +252,8 @@ public class Catalina {
                 isConfig = false;
             } else if (arg.equals("-config")) {
                 isConfig = true;
+            } else if (arg.equals("-generateCode")) {
+                generateCode = true;
             } else if (arg.equals("-nonaming")) {
                 setUseNaming(false);
             } else if (arg.equals("-help")) {
@@ -278,7 +295,6 @@ public class Catalina {
      * @return the main digester to parse server.xml
      */
     protected Digester createStartDigester() {
-        long t1=System.currentTimeMillis();
         // Initialize the digester
         Digester digester = new Digester();
         digester.setValidating(false);
@@ -348,11 +364,10 @@ public class Catalina {
                             "addExecutor",
                             "org.apache.catalina.Executor");
 
-
         digester.addRule("Server/Service/Connector",
                          new ConnectorCreateRule());
-        digester.addRule("Server/Service/Connector", new SetAllPropertiesRule(
-                new String[]{"executor", "sslImplementationName", 
"protocol"}));
+        digester.addSetProperties("Server/Service/Connector",
+                new String[]{"executor", "sslImplementationName", "protocol"});
         digester.addSetNext("Server/Service/Connector",
                             "addConnector",
                             "org.apache.catalina.connector.Connector");
@@ -368,8 +383,7 @@ public class Catalina {
 
         digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
                          new CertificateCreateRule());
-        digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
-                         new SetAllPropertiesRule(new String[]{"type"}));
+        
digester.addSetProperties("Server/Service/Connector/SSLHostConfig/Certificate", 
new String[]{"type"});
         
digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",
                             "addCertificate",
                             
"org.apache.tomcat.util.net.SSLHostConfigCertificate");
@@ -417,10 +431,6 @@ public class Catalina {
                          new SetParentClassLoaderRule(parentClassLoader));
         addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
 
-        long t2=System.currentTimeMillis();
-        if (log.isDebugEnabled()) {
-            log.debug("Digester for server.xml created " + ( t2-t1 ));
-        }
         return digester;
 
     }
@@ -555,15 +565,44 @@ public class Catalina {
         ConfigFileLoader.setSource(new 
CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), 
getConfigFile()));
         File file = configFile();
 
-        // Create and execute our Digester
-        Digester digester = createStartDigester();
-
         try (ConfigurationSource.Resource resource = 
ConfigFileLoader.getSource().getServerXml()) {
-            InputStream inputStream = resource.getInputStream();
-            InputSource inputSource = new 
InputSource(resource.getURI().toURL().toString());
-            inputSource.setByteStream(inputStream);
-            digester.push(this);
-            digester.parse(inputSource);
+            String serverXmlId = String.valueOf(resource.getLastModified());
+            String serverXmlClassName = "catalina.ServerXml_" + serverXmlId;
+            ServerXml serverXml = null;
+            try {
+                serverXml = (ServerXml) 
Catalina.class.getClassLoader().loadClass(serverXmlClassName).newInstance();
+            } catch (ClassNotFoundException e) {
+                // Ignore, no generated code found
+            }
+            if (serverXml != null) {
+                serverXml.load(this);
+            } else {
+                // 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()));
+                }
+                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());
+                            }
+                        }
+                    }
+                }
+            }
         } catch (Exception e) {
             log.warn(sm.getString("catalina.configFail", 
file.getAbsolutePath()), e);
             if (file.exists() && !file.canRead()) {
@@ -590,9 +629,8 @@ public class Catalina {
             }
         }
 
-        long t2 = System.nanoTime();
         if(log.isInfoEnabled()) {
-            log.info(sm.getString("catalina.init", Long.valueOf((t2 - t1) / 
1000000)));
+            log.info(sm.getString("catalina.init", 
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t1)));
         }
     }
 
@@ -788,6 +826,28 @@ public class Catalina {
     }
 
 
+    protected void generateClassHeader(Digester digester, String time) {
+        StringBuilder code = digester.getGeneratedCode();
+        code.append("package catalina;").append(System.lineSeparator());
+        code.append("public class ServerXml_").append(time).append(" 
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());
+    }
+
+
+    protected void generateClassFooter(Digester digester) {
+        StringBuilder code = digester.getGeneratedCode();
+        code.append("}").append(System.lineSeparator());
+        code.append("}").append(System.lineSeparator());
+    }
+
+
+    public interface ServerXml {
+        public void load(Catalina catalina);
+    }
+
+
     // --------------------------------------- CatalinaShutdownHook Inner Class
 
     // XXX Should be moved to embedded !
@@ -819,39 +879,41 @@ public class Catalina {
 
     private static final Log log = LogFactory.getLog(Catalina.class);
 
-}
 
+    /**
+     * Rule that sets the parent class loader for the top object on the stack,
+     * which must be a <code>Container</code>.
+     */
 
-// ------------------------------------------------------------ Private Classes
-
+    final class SetParentClassLoaderRule extends Rule {
 
-/**
- * Rule that sets the parent class loader for the top object on the stack,
- * which must be a <code>Container</code>.
- */
+        public SetParentClassLoaderRule(ClassLoader parentClassLoader) {
 
-final class SetParentClassLoaderRule extends Rule {
+            this.parentClassLoader = parentClassLoader;
 
-    public SetParentClassLoaderRule(ClassLoader parentClassLoader) {
+        }
 
-        this.parentClassLoader = parentClassLoader;
+        ClassLoader parentClassLoader = null;
 
-    }
+        @Override
+        public void begin(String namespace, String name, Attributes attributes)
+            throws Exception {
 
-    ClassLoader parentClassLoader = null;
+            if (digester.getLogger().isDebugEnabled()) {
+                digester.getLogger().debug("Setting parent class loader");
+            }
 
-    @Override
-    public void begin(String namespace, String name, Attributes attributes)
-        throws Exception {
+            Container top = (Container) digester.peek();
+            top.setParentClassLoader(parentClassLoader);
 
-        if (digester.getLogger().isDebugEnabled()) {
-            digester.getLogger().debug("Setting parent class loader");
+            StringBuilder code = digester.getGeneratedCode();
+            if (code != null) {
+                
code.append(digester.toVariableName(top)).append(".setParentClassLoader(");
+                
code.append(digester.toVariableName(Catalina.this)).append(".getParentClassLoader());");
+                code.append(System.lineSeparator());
+            }
         }
 
-        Container top = (Container) digester.peek();
-        top.setParentClassLoader(parentClassLoader);
-
     }
 
-
 }
diff --git a/java/org/apache/catalina/startup/CertificateCreateRule.java 
b/java/org/apache/catalina/startup/CertificateCreateRule.java
index 1db3c70..f41c001 100644
--- a/java/org/apache/catalina/startup/CertificateCreateRule.java
+++ b/java/org/apache/catalina/startup/CertificateCreateRule.java
@@ -29,7 +29,7 @@ public class CertificateCreateRule extends Rule {
 
     @Override
     public void begin(String namespace, String name, Attributes attributes) 
throws Exception {
-        SSLHostConfig sslHostConfig = (SSLHostConfig)digester.peek();
+        SSLHostConfig sslHostConfig = (SSLHostConfig) digester.peek();
 
         Type type;
         String typeValue = attributes.getValue("type");
@@ -42,6 +42,15 @@ public class CertificateCreateRule extends Rule {
         SSLHostConfigCertificate certificate = new 
SSLHostConfigCertificate(sslHostConfig, type);
 
         digester.push(certificate);
+
+        StringBuilder code = digester.getGeneratedCode();
+        if (code != null) {
+            code.append(SSLHostConfigCertificate.class.getName()).append(" 
").append(digester.toVariableName(certificate));
+            code.append(" = new 
").append(SSLHostConfigCertificate.class.getName());
+            code.append("(").append(digester.toVariableName(sslHostConfig));
+            code.append(", ").append(Type.class.getName().replace('$', 
'.')).append(".").append(type).append(");");
+            code.append(System.lineSeparator());
+        }
     }
 
 
diff --git a/java/org/apache/catalina/startup/ConnectorCreateRule.java 
b/java/org/apache/catalina/startup/ConnectorCreateRule.java
index 83e488c..a1b53d9 100644
--- a/java/org/apache/catalina/startup/ConnectorCreateRule.java
+++ b/java/org/apache/catalina/startup/ConnectorCreateRule.java
@@ -24,6 +24,7 @@ import java.lang.reflect.Method;
 import org.apache.catalina.Executor;
 import org.apache.catalina.Service;
 import org.apache.catalina.connector.Connector;
+import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.IntrospectionUtils;
@@ -56,12 +57,14 @@ public class ConnectorCreateRule extends Rule {
     @Override
     public void begin(String namespace, String name, Attributes attributes)
             throws Exception {
-        Service svc = (Service)digester.peek();
+        Service svc = (Service) digester.peek();
         Executor ex = null;
-        if ( attributes.getValue("executor")!=null ) {
-            ex = svc.getExecutor(attributes.getValue("executor"));
+        String executorName = attributes.getValue("executor");
+        if (executorName != null ) {
+            ex = svc.getExecutor(executorName);
         }
-        Connector con = new Connector(attributes.getValue("protocol"));
+        String protocolName = attributes.getValue("protocol");
+        Connector con = new Connector(protocolName);
         if (ex != null) {
             setExecutor(con, ex);
         }
@@ -70,6 +73,26 @@ public class ConnectorCreateRule extends Rule {
             setSSLImplementationName(con, sslImplementationName);
         }
         digester.push(con);
+
+        StringBuilder code = digester.getGeneratedCode();
+        if (code != null) {
+            code.append(Connector.class.getName()).append(" 
").append(digester.toVariableName(con));
+            code.append(" = new ").append(Connector.class.getName());
+            code.append("(new 
").append(con.getProtocolHandlerClassName()).append("());");
+            code.append(System.lineSeparator());
+            if (ex != null) {
+                
code.append(digester.toVariableName(con)).append(".getProtocolHandler().setExecutor(");
+                
code.append(digester.toVariableName(svc)).append(".getExecutor(").append(executorName);
+                code.append("));");
+                code.append(System.lineSeparator());
+            }
+            if (sslImplementationName != null) {
+                
code.append("((").append(AbstractHttp11JsseProtocol.class.getName()).append("<?>)
 ");
+                
code.append(digester.toVariableName(con)).append(".getProtocolHandler()).setSslImplementationName(\"");
+                code.append(sslImplementationName).append("\");");
+                code.append(System.lineSeparator());
+            }
+        }
     }
 
     private static void setExecutor(Connector con, Executor ex) throws 
Exception {
diff --git a/java/org/apache/catalina/startup/ContextRuleSet.java 
b/java/org/apache/catalina/startup/ContextRuleSet.java
index 3476317..e230d54 100644
--- a/java/org/apache/catalina/startup/ContextRuleSet.java
+++ b/java/org/apache/catalina/startup/ContextRuleSet.java
@@ -98,7 +98,7 @@ public class ContextRuleSet implements RuleSet {
                     "org.apache.catalina.core.StandardContext", "className");
             digester.addSetProperties(prefix + "Context");
         } else {
-            digester.addRule(prefix + "Context", new 
SetContextPropertiesRule());
+            digester.addSetProperties(prefix + "Context", new String[]{"path", 
"docBase"});
         }
 
         if (create) {
diff --git a/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java 
b/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java
index 8bf60c6..20a8c8a 100644
--- a/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java
+++ b/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java
@@ -71,6 +71,12 @@ public class CopyParentClassLoaderRule extends Rule {
             (ClassLoader) method.invoke(parent, new Object[0]);
         child.setParentClassLoader(classLoader);
 
+        StringBuilder code = digester.getGeneratedCode();
+        if (code != null) {
+            
code.append(digester.toVariableName(child)).append(".setParentClassLoader(");
+            
code.append(digester.toVariableName(parent)).append(".getParentClassLoader());");
+            code.append(System.lineSeparator());
+        }
     }
 
 
diff --git a/java/org/apache/catalina/startup/LifecycleListenerRule.java 
b/java/org/apache/catalina/startup/LifecycleListenerRule.java
index f70a7b2..d65bf59 100644
--- a/java/org/apache/catalina/startup/LifecycleListenerRule.java
+++ b/java/org/apache/catalina/startup/LifecycleListenerRule.java
@@ -128,6 +128,12 @@ public class LifecycleListenerRule extends Rule {
 
         // Add this LifecycleListener to our associated component
         c.addLifecycleListener(listener);
+
+        StringBuilder code = digester.getGeneratedCode();
+        if (code != null) {
+            
code.append(digester.toVariableName(c)).append(".addLifecycleListener(");
+            code.append("new 
").append(className).append("());").append(System.lineSeparator());
+        }
     }
 
 
diff --git a/java/org/apache/catalina/startup/NamingRuleSet.java 
b/java/org/apache/catalina/startup/NamingRuleSet.java
index dc5fbb3..b2a3baa 100644
--- a/java/org/apache/catalina/startup/NamingRuleSet.java
+++ b/java/org/apache/catalina/startup/NamingRuleSet.java
@@ -75,7 +75,7 @@ public class NamingRuleSet implements RuleSet {
 
         digester.addObjectCreate(prefix + "Ejb",
                                  
"org.apache.tomcat.util.descriptor.web.ContextEjb");
-        digester.addRule(prefix + "Ejb", new SetAllPropertiesRule());
+        digester.addSetProperties(prefix + "Ejb");
         digester.addRule(prefix + "Ejb",
                 new SetNextNamingRule("addEjb",
                             
"org.apache.tomcat.util.descriptor.web.ContextEjb"));
@@ -89,35 +89,35 @@ public class NamingRuleSet implements RuleSet {
 
         digester.addObjectCreate(prefix + "LocalEjb",
                                  
"org.apache.tomcat.util.descriptor.web.ContextLocalEjb");
-        digester.addRule(prefix + "LocalEjb", new SetAllPropertiesRule());
+        digester.addSetProperties(prefix + "LocalEjb");
         digester.addRule(prefix + "LocalEjb",
                 new SetNextNamingRule("addLocalEjb",
                             
"org.apache.tomcat.util.descriptor.web.ContextLocalEjb"));
 
         digester.addObjectCreate(prefix + "Resource",
                                  
"org.apache.tomcat.util.descriptor.web.ContextResource");
-        digester.addRule(prefix + "Resource", new SetAllPropertiesRule());
+        digester.addSetProperties(prefix + "Resource");
         digester.addRule(prefix + "Resource",
                 new SetNextNamingRule("addResource",
                             
"org.apache.tomcat.util.descriptor.web.ContextResource"));
 
         digester.addObjectCreate(prefix + "ResourceEnvRef",
             "org.apache.tomcat.util.descriptor.web.ContextResourceEnvRef");
-        digester.addRule(prefix + "ResourceEnvRef", new 
SetAllPropertiesRule());
+        digester.addSetProperties(prefix + "ResourceEnvRef");
         digester.addRule(prefix + "ResourceEnvRef",
                 new SetNextNamingRule("addResourceEnvRef",
                             
"org.apache.tomcat.util.descriptor.web.ContextResourceEnvRef"));
 
         digester.addObjectCreate(prefix + "ServiceRef",
             "org.apache.tomcat.util.descriptor.web.ContextService");
-        digester.addRule(prefix + "ServiceRef", new SetAllPropertiesRule());
+        digester.addSetProperties(prefix + "ServiceRef");
         digester.addRule(prefix + "ServiceRef",
                 new SetNextNamingRule("addService",
                             
"org.apache.tomcat.util.descriptor.web.ContextService"));
 
         digester.addObjectCreate(prefix + "Transaction",
             "org.apache.tomcat.util.descriptor.web.ContextTransaction");
-        digester.addRule(prefix + "Transaction", new SetAllPropertiesRule());
+        digester.addSetProperties(prefix + "Transaction");
         digester.addRule(prefix + "Transaction",
                 new SetNextNamingRule("setTransaction",
                             
"org.apache.tomcat.util.descriptor.web.ContextTransaction"));
diff --git a/java/org/apache/catalina/startup/SetAllPropertiesRule.java 
b/java/org/apache/catalina/startup/SetAllPropertiesRule.java
index 5115e32..93d59e9 100644
--- a/java/org/apache/catalina/startup/SetAllPropertiesRule.java
+++ b/java/org/apache/catalina/startup/SetAllPropertiesRule.java
@@ -18,62 +18,24 @@
 
 package org.apache.catalina.startup;
 
-import java.util.HashMap;
-
-import org.apache.tomcat.util.IntrospectionUtils;
-import org.apache.tomcat.util.digester.Rule;
-import org.xml.sax.Attributes;
+import org.apache.tomcat.util.digester.SetPropertiesRule;
 
 /**
  * Rule that uses the introspection utils to set properties.
  *
  * @author Remy Maucherat
+ * @deprecated This will be removed in Tomcat 10
  */
-public class SetAllPropertiesRule extends Rule {
+public class SetAllPropertiesRule extends SetPropertiesRule {
 
 
     // ----------------------------------------------------------- Constructors
-    public SetAllPropertiesRule() {}
-
-    public SetAllPropertiesRule(String[] exclude) {
-        for (String s : exclude) if (s != null) this.excludes.put(s, s);
+    public SetAllPropertiesRule() {
+        super();
     }
 
-    // ----------------------------------------------------- Instance Variables
-    protected final HashMap<String,String> excludes = new HashMap<>();
-
-    // --------------------------------------------------------- Public Methods
-
-
-    /**
-     * Handle the beginning of an XML element.
-     *
-     * @param attributes The attributes of this element
-     *
-     * @exception Exception if a processing error occurs
-     */
-    @Override
-    public void begin(String namespace, String nameX, Attributes attributes)
-        throws Exception {
-
-        for (int i = 0; i < attributes.getLength(); i++) {
-            String name = attributes.getLocalName(i);
-            if ("".equals(name)) {
-                name = attributes.getQName(i);
-            }
-            String value = attributes.getValue(i);
-            if ( !excludes.containsKey(name)) {
-                if (!digester.isFakeAttribute(digester.peek(), name)
-                        && !IntrospectionUtils.setProperty(digester.peek(), 
name, value)
-                        && digester.getRulesValidation()) {
-                    digester.getLogger().warn("[SetAllPropertiesRule]{" + 
digester.getMatch() +
-                            "} Setting property '" + name + "' to '" +
-                            value + "' did not find a matching property.");
-                }
-            }
-        }
-
+    public SetAllPropertiesRule(String[] exclude) {
+        super(exclude);
     }
 
-
 }
diff --git a/java/org/apache/catalina/startup/SetContextPropertiesRule.java 
b/java/org/apache/catalina/startup/SetContextPropertiesRule.java
index c9e58a6..fda8742 100644
--- a/java/org/apache/catalina/startup/SetContextPropertiesRule.java
+++ b/java/org/apache/catalina/startup/SetContextPropertiesRule.java
@@ -18,21 +18,23 @@
 
 package org.apache.catalina.startup;
 
-import org.apache.tomcat.util.IntrospectionUtils;
-import org.apache.tomcat.util.digester.Rule;
-import org.xml.sax.Attributes;
+import org.apache.tomcat.util.digester.SetPropertiesRule;
 
 /**
  * Rule that uses the introspection utils to set properties of a context
  * (everything except "path").
  *
  * @author Remy Maucherat
+ * @deprecated This will be removed in Tomcat 10
  */
-public class SetContextPropertiesRule extends Rule {
+public class SetContextPropertiesRule extends SetPropertiesRule {
 
 
     // ----------------------------------------------------------- Constructors
 
+    public SetContextPropertiesRule() {
+        super(new String[]{"path", "docBase"});
+    }
 
     // ----------------------------------------------------- Instance Variables
 
@@ -40,36 +42,4 @@ public class SetContextPropertiesRule extends Rule {
     // --------------------------------------------------------- Public Methods
 
 
-    /**
-     * Handle the beginning of an XML element.
-     *
-     * @param attributes The attributes of this element
-     *
-     * @exception Exception if a processing error occurs
-     */
-    @Override
-    public void begin(String namespace, String nameX, Attributes attributes)
-        throws Exception {
-
-        for (int i = 0; i < attributes.getLength(); i++) {
-            String name = attributes.getLocalName(i);
-            if ("".equals(name)) {
-                name = attributes.getQName(i);
-            }
-            if ("path".equals(name) || "docBase".equals(name)) {
-                continue;
-            }
-            String value = attributes.getValue(i);
-            if (!digester.isFakeAttribute(digester.peek(), name)
-                    && !IntrospectionUtils.setProperty(digester.peek(), name, 
value)
-                    && digester.getRulesValidation()) {
-                digester.getLogger().warn("[SetContextPropertiesRule]{" + 
digester.getMatch() +
-                        "} Setting property '" + name + "' to '" +
-                        value + "' did not find a matching property.");
-            }
-        }
-
-    }
-
-
 }
diff --git a/java/org/apache/catalina/startup/SetNextNamingRule.java 
b/java/org/apache/catalina/startup/SetNextNamingRule.java
index c82fe06..cf94b7c 100644
--- a/java/org/apache/catalina/startup/SetNextNamingRule.java
+++ b/java/org/apache/catalina/startup/SetNextNamingRule.java
@@ -21,6 +21,7 @@ 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;
 
 
@@ -104,6 +105,12 @@ public class SetNextNamingRule extends Rule {
         IntrospectionUtils.callMethod1(namingResources, methodName,
                 child, paramType, digester.getClassLoader());
 
+        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(");");
+            code.append(System.lineSeparator());
+        }
     }
 
 
diff --git a/java/org/apache/tomcat/util/IntrospectionUtils.java 
b/java/org/apache/tomcat/util/IntrospectionUtils.java
index 22bf92a..4355882 100644
--- a/java/org/apache/tomcat/util/IntrospectionUtils.java
+++ b/java/org/apache/tomcat/util/IntrospectionUtils.java
@@ -45,12 +45,17 @@ public final class IntrospectionUtils {
      * @return <code>true</code> if operation was successful
      */
     public static boolean setProperty(Object o, String name, String value) {
-        return setProperty(o,name,value,true);
+        return setProperty(o, name, value, true, null);
     }
 
-    @SuppressWarnings("null") // setPropertyMethodVoid is not null when used
     public static boolean setProperty(Object o, String name, String value,
             boolean invokeSetProperty) {
+        return setProperty(o, name, value, invokeSetProperty, null);
+    }
+
+    @SuppressWarnings("null") // setPropertyMethodVoid is not null when used
+    public static boolean setProperty(Object o, String name, String value,
+            boolean invokeSetProperty, StringBuilder actualMethod) {
         if (log.isDebugEnabled())
             log.debug("IntrospectionUtils: setProperty(" +
                     o.getClass() + " " + name + "=" + value + ")");
@@ -67,8 +72,10 @@ public final class IntrospectionUtils {
                 Class<?> paramT[] = item.getParameterTypes();
                 if (setter.equals(item.getName()) && paramT.length == 1
                         && "java.lang.String".equals(paramT[0].getName())) {
-
                     item.invoke(o, new Object[]{value});
+                    if (actualMethod != null) {
+                        
actualMethod.append(item.getName()).append("(\"").append(value).append("\")");
+                    }
                     return true;
                 }
             }
@@ -91,6 +98,9 @@ public final class IntrospectionUtils {
                         } catch (NumberFormatException ex) {
                             ok = false;
                         }
+                        if (actualMethod != null) {
+                            
actualMethod.append(method.getName()).append("(Integer.valueOf(\"").append(value).append("\"))");
+                        }
                         // Try a setFoo ( long )
                     } else if ("java.lang.Long".equals(paramType.getName())
                             || "long".equals(paramType.getName())) {
@@ -99,12 +109,16 @@ public final class IntrospectionUtils {
                         } catch (NumberFormatException ex) {
                             ok = false;
                         }
-
+                        if (actualMethod != null) {
+                            
actualMethod.append(method.getName()).append("(Long.valueOf(\"").append(value).append("\"))");
+                        }
                         // Try a setFoo ( boolean )
                     } else if ("java.lang.Boolean".equals(paramType.getName())
                             || "boolean".equals(paramType.getName())) {
                         params[0] = Boolean.valueOf(value);
-
+                        if (actualMethod != null) {
+                            
actualMethod.append(method.getName()).append("(Boolean.valueOf(\"").append(value).append("\"))");
+                        }
                         // Try a setFoo ( InetAddress )
                     } else if ("java.net.InetAddress".equals(paramType
                             .getName())) {
@@ -115,7 +129,9 @@ public final class IntrospectionUtils {
                                 log.debug("IntrospectionUtils: Unable to 
resolve host name:" + value);
                             ok = false;
                         }
-
+                        if (actualMethod != null) {
+                            
actualMethod.append(method.getName()).append("(InetAddress.getByName(\"").append(value).append("\"))");
+                        }
                         // Unknown type
                     } else {
                         if (log.isDebugEnabled())
@@ -143,6 +159,9 @@ public final class IntrospectionUtils {
             // Ok, no setXXX found, try a setProperty("name", "value")
             if (invokeSetProperty && (setPropertyMethodBool != null ||
                     setPropertyMethodVoid != null)) {
+                if (actualMethod != null) {
+                    
actualMethod.append("setProperty(\"").append(name).append("\", 
\"").append(value).append("\")");
+                }
                 Object params[] = new Object[2];
                 params[0] = name;
                 params[1] = value;
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextEjb.java 
b/java/org/apache/tomcat/util/descriptor/web/ContextEjb.java
index 4190253..8e2b177 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextEjb.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextEjb.java
@@ -30,6 +30,10 @@ public class ContextEjb extends ResourceBase {
 
     private static final long serialVersionUID = 1L;
 
+    public ContextEjb() {
+        initialHashCode = hashCode();
+    }
+
     // ------------------------------------------------------------- Properties
 
 
diff --git a/java/org/apache/tomcat/util/descriptor/web/ContextEnvironment.java 
b/java/org/apache/tomcat/util/descriptor/web/ContextEnvironment.java
index f51b250..b606961 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextEnvironment.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextEnvironment.java
@@ -28,6 +28,10 @@ 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 c0ee25c..7b124aa 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextHandler.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextHandler.java
@@ -34,6 +34,10 @@ 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 29e8d5e..ecfc1e3 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextLocalEjb.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextLocalEjb.java
@@ -30,6 +30,10 @@ 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 dd3de30..b4115bd 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextResource.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextResource.java
@@ -30,6 +30,10 @@ 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 ba3169c..81b6aa6 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextResourceEnvRef.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextResourceEnvRef.java
@@ -29,6 +29,10 @@ 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 e50dcf9..6b88c07 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextResourceLink.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextResourceLink.java
@@ -30,6 +30,10 @@ 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 cefdc56..a8e2331 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ContextService.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ContextService.java
@@ -33,6 +33,10 @@ 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 be9fcfb..b4a97f2 100644
--- a/java/org/apache/tomcat/util/descriptor/web/MessageDestination.java
+++ b/java/org/apache/tomcat/util/descriptor/web/MessageDestination.java
@@ -29,6 +29,10 @@ 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 25d9f67..be8b44f 100644
--- a/java/org/apache/tomcat/util/descriptor/web/MessageDestinationRef.java
+++ b/java/org/apache/tomcat/util/descriptor/web/MessageDestinationRef.java
@@ -29,6 +29,10 @@ 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 37ec8fb..e191b46 100644
--- a/java/org/apache/tomcat/util/descriptor/web/ResourceBase.java
+++ b/java/org/apache/tomcat/util/descriptor/web/ResourceBase.java
@@ -96,6 +96,16 @@ 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 288312e..0d8c468 100644
--- a/java/org/apache/tomcat/util/digester/CallMethodRule.java
+++ b/java/org/apache/tomcat/util/digester/CallMethodRule.java
@@ -383,6 +383,20 @@ public class CallMethodRule extends Rule {
         Object result = IntrospectionUtils.callMethodN(target, methodName,
                 paramValues, paramTypes);
         processMethodCallResult(result);
+
+        StringBuilder code = digester.getGeneratedCode();
+        if (code != null) {
+            
code.append(digester.toVariableName(target)).append(".").append(methodName);
+            code.append("(");
+            for (int i = 0; i < paramValues.length; i++) {
+                if (i > 0) {
+                    code.append(",");
+                }
+                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 6af109d..9ef59a4 100644
--- a/java/org/apache/tomcat/util/digester/Digester.java
+++ b/java/org/apache/tomcat/util/digester/Digester.java
@@ -352,6 +352,10 @@ public class Digester extends DefaultHandler2 {
      */
     protected Log saxLog = 
LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax");
 
+    /**
+     * Generated code.
+     */
+    protected StringBuilder code = null;
 
     public Digester() {
         propertySourcesSet = true;
@@ -386,6 +390,22 @@ public class Digester extends DefaultHandler2 {
     }
 
 
+    public void startGeneratingCode() {
+        code = new StringBuilder();
+    }
+
+    public StringBuilder getGeneratedCode() {
+        return code;
+    }
+
+    public String toVariableName(Object object) {
+        return toVariableName(object, object.hashCode());
+    }
+
+    public String toVariableName(Object object, int hashCode) {
+        return "tc_" + object.getClass().getSimpleName() + "_" + 
String.valueOf(Math.abs(hashCode));
+    }
+
     // ------------------------------------------------------------- Properties
 
     /**
@@ -1678,6 +1698,13 @@ public class Digester extends DefaultHandler2 {
     }
 
 
+    public void addSetProperties(String pattern, String[] excludes) {
+
+        addRule(pattern, new SetPropertiesRule(excludes));
+
+    }
+
+
     // --------------------------------------------------- Object Stack Methods
 
 
diff --git a/java/org/apache/tomcat/util/digester/ObjectCreateRule.java 
b/java/org/apache/tomcat/util/digester/ObjectCreateRule.java
index 21d0f11..18e1e0b 100644
--- a/java/org/apache/tomcat/util/digester/ObjectCreateRule.java
+++ b/java/org/apache/tomcat/util/digester/ObjectCreateRule.java
@@ -104,6 +104,12 @@ public class ObjectCreateRule extends Rule {
         Class<?> clazz = digester.getClassLoader().loadClass(realClassName);
         Object instance = clazz.getConstructor().newInstance();
         digester.push(instance);
+
+        StringBuilder code = digester.getGeneratedCode();
+        if (code != null) {
+            code.append(realClassName).append(" 
").append(digester.toVariableName(instance)).append(" = new ");
+            
code.append(realClassName).append("();").append(System.lineSeparator());
+        }
     }
 
 
@@ -143,6 +149,10 @@ public class ObjectCreateRule extends Rule {
                     "} Pop " + top.getClass().getName());
         }
 
+        StringBuilder code = digester.getGeneratedCode();
+        if (code != null) {
+            code.append(System.lineSeparator());
+        }
     }
 
 
diff --git a/java/org/apache/tomcat/util/digester/SetNextRule.java 
b/java/org/apache/tomcat/util/digester/SetNextRule.java
index bb8eb9f..1fa14f3 100644
--- a/java/org/apache/tomcat/util/digester/SetNextRule.java
+++ b/java/org/apache/tomcat/util/digester/SetNextRule.java
@@ -145,6 +145,12 @@ public class SetNextRule extends Rule {
         IntrospectionUtils.callMethod1(parent, methodName,
                 child, paramType, digester.getClassLoader());
 
+        StringBuilder code = digester.getGeneratedCode();
+        if (code != null) {
+            code.append(digester.toVariableName(parent)).append(".");
+            
code.append(methodName).append("(").append(digester.toVariableName(child)).append(");");
+            code.append(System.lineSeparator());
+        }
     }
 
 
diff --git a/java/org/apache/tomcat/util/digester/SetPropertiesRule.java 
b/java/org/apache/tomcat/util/digester/SetPropertiesRule.java
index 78c976c..23a1e1a 100644
--- a/java/org/apache/tomcat/util/digester/SetPropertiesRule.java
+++ b/java/org/apache/tomcat/util/digester/SetPropertiesRule.java
@@ -19,6 +19,8 @@
 package org.apache.tomcat.util.digester;
 
 
+import java.util.HashMap;
+
 import org.apache.tomcat.util.IntrospectionUtils;
 import org.xml.sax.Attributes;
 
@@ -34,6 +36,21 @@ public class SetPropertiesRule extends Rule {
         void endSetPropertiesRule();
     }
 
+    protected final HashMap<String,String> excludes;
+
+    public SetPropertiesRule() {
+        excludes = null;
+    }
+
+    public SetPropertiesRule(String[] exclude) {
+        excludes = new HashMap<>();
+        for (String s : exclude) {
+            if (s != null) {
+                this.excludes.put(s, s);
+            }
+        }
+    }
+
     /**
      * Process the beginning of this element.
      *
@@ -60,6 +77,11 @@ public class SetPropertiesRule extends Rule {
                                    "} Set NULL properties");
             }
         }
+        StringBuilder code = digester.getGeneratedCode();
+        String variableName = null;
+        if (code != null) {
+            variableName = digester.toVariableName(top);
+        }
 
         for (int i = 0; i < attributes.getLength(); i++) {
             String name = attributes.getLocalName(i);
@@ -74,18 +96,36 @@ public class SetPropertiesRule extends Rule {
                         value + "'");
             }
             if (!digester.isFakeAttribute(top, name)
-                    && !IntrospectionUtils.setProperty(top, name, value)
-                    && digester.getRulesValidation()) {
-                if (!"optional".equals(name)) {
-                    digester.log.warn(sm.getString("rule.noProperty", 
digester.match, name, value));
+                    && (excludes == null || (excludes != null && 
!excludes.containsKey(name)))) {
+                StringBuilder actualMethod = null;
+                if (code != null) {
+                    actualMethod = new StringBuilder();
+                }
+                if (!IntrospectionUtils.setProperty(top, name, value, true, 
actualMethod)) {
+                    if (digester.getRulesValidation() && 
!"optional".equals(name)) {
+                        digester.log.warn(sm.getString("rule.noProperty", 
digester.match, name, value));
+                    }
+                } else {
+                    if (code != null) {
+                        
code.append(variableName).append(".").append(actualMethod).append(";");
+                        code.append(System.lineSeparator());
+                    }
                 }
             }
         }
 
         if (top instanceof Listener) {
             ((Listener) top).endSetPropertiesRule();
+            if (code != null) {
+                
code.append("((org.apache.tomcat.util.digester.SetPropertiesRule.Listener) ");
+                code.append(variableName).append(").endSetPropertiesRule();");
+                code.append(System.lineSeparator());
+            }
         }
 
+        if (code != null) {
+            code.append(System.lineSeparator());
+        }
     }
 
 


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

Reply via email to