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


The following commit(s) were added to refs/heads/9.0.x by this push:
     new b8669f7  Add a dedicated loader for generated code
b8669f7 is described below

commit b8669f777de284d18a55993afb0e4847a35c195b
Author: remm <r...@apache.org>
AuthorDate: Tue Jul 21 11:19:07 2020 +0200

    Add a dedicated loader for generated code
    
    This avoids dynamic classloading, and calling the classaloder for not
    found xml.
---
 java/org/apache/catalina/startup/Catalina.java     | 59 +++++++++++++++++++---
 .../org/apache/catalina/startup/ContextConfig.java | 21 +++-----
 .../catalina/startup/LocalStrings.properties       |  1 +
 java/org/apache/tomcat/util/digester/Digester.java | 34 +++++++++++++
 webapps/docs/changelog.xml                         |  4 ++
 5 files changed, 98 insertions(+), 21 deletions(-)

diff --git a/java/org/apache/catalina/startup/Catalina.java 
b/java/org/apache/catalina/startup/Catalina.java
index 9683df9..134a236 100644
--- a/java/org/apache/catalina/startup/Catalina.java
+++ b/java/org/apache/catalina/startup/Catalina.java
@@ -554,8 +554,30 @@ public class Catalina {
         ConfigFileLoader.setSource(new 
CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), 
getConfigFile()));
         File file = configFile();
 
+        if (useGeneratedCode && !Digester.isGeneratedCodeLoaderSet()) {
+            // Load loader
+            String loaderClassName = generatedCodePackage + 
".DigesterGeneratedCodeLoader";
+            try {
+                Digester.GeneratedCodeLoader loader =
+                        (Digester.GeneratedCodeLoader) 
Catalina.class.getClassLoader().loadClass(loaderClassName).newInstance();
+                Digester.setGeneratedCodeLoader(loader);
+            } catch (Exception e) {
+                if (log.isDebugEnabled()) {
+                    log.info(sm.getString("catalina.noLoader", 
loaderClassName), e);
+                } else {
+                    log.info(sm.getString("catalina.noLoader", 
loaderClassName));
+                }
+                // No loader so don't use generated code
+                useGeneratedCode = false;
+            }
+        }
+
         // Init source location
         File serverXmlLocation = null;
+        String xmlClassName = null;
+        if (generateCode || useGeneratedCode) {
+            xmlClassName = start ? generatedCodePackage + ".ServerXml" : 
generatedCodePackage + ".ServerXmlStop";
+        }
         if (generateCode) {
             if (generatedCodeLocationParameter != null) {
                 generatedCodeLocation = new 
File(generatedCodeLocationParameter);
@@ -575,12 +597,7 @@ public class Catalina {
 
         ServerXml serverXml = null;
         if (useGeneratedCode) {
-            String xmlClassName = start ? generatedCodePackage + ".ServerXml" 
: generatedCodePackage + ".ServerXmlStop";
-            try {
-                serverXml = (ServerXml) 
Catalina.class.getClassLoader().loadClass(xmlClassName).newInstance();
-            } catch (Exception e) {
-                // Ignore, no generated code found
-            }
+            serverXml = (ServerXml) Digester.loadGeneratedClass(xmlClassName);
         }
 
         if (serverXml != null) {
@@ -605,6 +622,7 @@ public class Catalina {
                         writer.write(digester.getGeneratedCode().toString());
                     }
                     digester.endGeneratingCode();
+                    Digester.addGeneratedClass(xmlClassName);
                 }
             } catch (Exception e) {
                 log.warn(sm.getString("catalina.configFail", 
file.getAbsolutePath()), e);
@@ -766,6 +784,11 @@ public class Catalina {
             log.info(sm.getString("catalina.startup", 
Long.toString(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t1))));
         }
 
+        if (generateCode) {
+            // Generate loader which will load all generated classes
+            generateLoader();
+        }
+
         // Register shutdown hook
         if (useShutdownHook) {
             if (shutdownHook == null) {
@@ -908,6 +931,30 @@ public class Catalina {
     }
 
 
+    protected void generateLoader() {
+        String loaderClassName = "DigesterGeneratedCodeLoader";
+        StringBuilder code = new StringBuilder();
+        code.append("package 
").append(generatedCodePackage).append(";").append(System.lineSeparator());
+        code.append("public class ").append(loaderClassName);
+        code.append(" implements 
org.apache.tomcat.util.digester.Digester.GeneratedCodeLoader 
{").append(System.lineSeparator());
+        code.append("public Object loadGeneratedCode(String className) 
{").append(System.lineSeparator());
+        code.append("switch (className) {").append(System.lineSeparator());
+        for (String generatedClassName : Digester.getGeneratedClasses()) {
+            code.append("case \"").append(generatedClassName).append("\" : 
return new ").append(generatedClassName);
+            code.append("();").append(System.lineSeparator());
+        }
+        code.append("default: return null; }").append(System.lineSeparator());
+        code.append("}}").append(System.lineSeparator());
+        File loaderLocation = new File(generatedCodeLocation, 
generatedCodePackage);
+        try (FileWriter writer = new FileWriter(new File(loaderLocation, 
loaderClassName + ".java"))) {
+            writer.write(code.toString());
+        } catch (IOException e) {
+            // Should not happen
+            log.debug("Error writing code loader", e);
+        }
+    }
+
+
     protected void generateClassHeader(Digester digester, boolean start) {
         StringBuilder code = digester.getGeneratedCode();
         code.append("package 
").append(generatedCodePackage).append(";").append(System.lineSeparator());
diff --git a/java/org/apache/catalina/startup/ContextConfig.java 
b/java/org/apache/catalina/startup/ContextConfig.java
index 4a79c2c..d2e092b 100644
--- a/java/org/apache/catalina/startup/ContextConfig.java
+++ b/java/org/apache/catalina/startup/ContextConfig.java
@@ -589,11 +589,7 @@ public class ContextConfig implements LifecycleListener {
                 contextXmlClassName = contextXmlPackageName + "." + 
contextXmlSimpleClassName;
             }
             if (useGeneratedCode) {
-                try {
-                    contextXml = (ContextXml) 
Catalina.class.getClassLoader().loadClass(contextXmlClassName).newInstance();
-                } catch (Exception e) {
-                    // Ignore, no generated code found
-                }
+                contextXml = (ContextXml) 
Digester.loadGeneratedClass(contextXmlClassName);
             }
             if (contextXml != null) {
                 contextXml.load(context);
@@ -614,6 +610,7 @@ public class ContextConfig implements LifecycleListener {
                             
writer.write(digester.getGeneratedCode().toString());
                         }
                         digester.endGeneratingCode();
+                        Digester.addGeneratedClass(contextXmlClassName);
                     }
                 } catch (MalformedURLException e) {
                     log.error(sm.getString("contextConfig.badUrl", 
defaultContextXml), e);
@@ -628,11 +625,7 @@ public class ContextConfig implements LifecycleListener {
                 contextXmlClassName = contextXmlPackageName + "." + 
contextXmlSimpleClassName;
             }
             if (useGeneratedCode) {
-                try {
-                    contextXml = (ContextXml) 
Catalina.class.getClassLoader().loadClass(contextXmlClassName).newInstance();
-                } catch (Exception e) {
-                    // Ignore, no generated code found
-                }
+                contextXml = (ContextXml) 
Digester.loadGeneratedClass(contextXmlClassName);
             }
             if (contextXml != null) {
                 contextXml.load(context);
@@ -654,6 +647,7 @@ public class ContextConfig implements LifecycleListener {
                             
writer.write(digester.getGeneratedCode().toString());
                         }
                         digester.endGeneratingCode();
+                        Digester.addGeneratedClass(contextXmlClassName);
                     }
                 } catch (MalformedURLException e) {
                     log.error(sm.getString("contextConfig.badUrl", 
hostContextFile), e);
@@ -670,11 +664,7 @@ public class ContextConfig implements LifecycleListener {
                 contextXmlClassName = contextXmlPackageName + "." + 
contextXmlSimpleClassName;
             }
             if (useGeneratedCode) {
-                try {
-                    contextXml = (ContextXml) 
Catalina.class.getClassLoader().loadClass(contextXmlClassName).newInstance();
-                } catch (Exception e) {
-                    // Ignore, no generated code found
-                }
+                contextXml = (ContextXml) 
Digester.loadGeneratedClass(contextXmlClassName);
             }
             if (contextXml != null) {
                 contextXml.load(context);
@@ -694,6 +684,7 @@ public class ContextConfig implements LifecycleListener {
                         // Ignore
                     }
                     digester.endGeneratingCode();
+                    Digester.addGeneratedClass(contextXmlClassName);
                 }
             }
         }
diff --git a/java/org/apache/catalina/startup/LocalStrings.properties 
b/java/org/apache/catalina/startup/LocalStrings.properties
index 2d242a0..92ee562 100644
--- a/java/org/apache/catalina/startup/LocalStrings.properties
+++ b/java/org/apache/catalina/startup/LocalStrings.properties
@@ -19,6 +19,7 @@ catalina.incorrectPermissions=Permissions incorrect, read 
permission is not allo
 catalina.init=Server initialization in [{0}] milliseconds
 catalina.initError=Error initializing Catalina
 catalina.noCluster=Cluster RuleSet not found due to [{0}]. Cluster 
configuration disabled.
+catalina.noLoader=Configuration code loader [{0}] was not found, generated 
code will not be used
 catalina.noNatming=Naming environment is disabled
 catalina.noServer=Cannot start server, server instance is not configured
 catalina.serverStartFail=The required Server component failed to start so 
Tomcat is unable to start.
diff --git a/java/org/apache/tomcat/util/digester/Digester.java 
b/java/org/apache/tomcat/util/digester/Digester.java
index 7153b52..0b76684 100644
--- a/java/org/apache/tomcat/util/digester/Digester.java
+++ b/java/org/apache/tomcat/util/digester/Digester.java
@@ -29,6 +29,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.EmptyStackException;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -138,6 +139,39 @@ public class Digester extends DefaultHandler2 {
         }
     }
 
+    private static final HashSet<String> generatedClasses = new HashSet<>();
+
+    public static void addGeneratedClass(String className) {
+        generatedClasses.add(className);
+    }
+
+    public static String[] getGeneratedClasses() {
+        return generatedClasses.toArray(new String[0]);
+    }
+
+    public interface GeneratedCodeLoader {
+        Object loadGeneratedCode(String className);
+    }
+
+    private static GeneratedCodeLoader generatedCodeLoader;
+
+    public static boolean isGeneratedCodeLoaderSet() {
+        return (Digester.generatedCodeLoader != null);
+    }
+
+    public static void setGeneratedCodeLoader(GeneratedCodeLoader 
generatedCodeLoader) {
+        if (Digester.generatedCodeLoader == null) {
+            Digester.generatedCodeLoader = generatedCodeLoader;
+        }
+    }
+
+    public static Object loadGeneratedClass(String className) {
+        if (generatedCodeLoader != null) {
+            return generatedCodeLoader.loadGeneratedCode(className);
+        }
+        return null;
+    }
+
     // --------------------------------------------------- Instance Variables
 
 
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index cc357a1..d2c1dd4 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -65,6 +65,10 @@
       <fix>
         Add missing code generation for remaining digester rules. (remm)
       </fix>
+      <update>
+        Add a dedicated loader for generated code to avoid dynamic class
+        loading. (remm)
+      </update>
     </changelog>
   </subsection>
   <subsection name="Coyote">


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

Reply via email to