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