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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]