SLING-4783 - The JavaScript scripting engine can generate classloader leaks
* implemented Rhino class cache cleaning if the current thread's class loader is a DynamicClassLoader
that's been marked as dirty
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1684189 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 59c6095..fff69e4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -177,6 +177,13 @@
<version>3.2.1</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.classloader</artifactId>
+ <version>1.3.0</version>
+ <scope>provided</scope>
+ </dependency>
+
<!-- Testing -->
<dependency>
<groupId>org.apache.sling</groupId>
diff --git a/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngine.java b/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngine.java
index 53d070d..b762ece 100644
--- a/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngine.java
+++ b/src/main/java/org/apache/sling/scripting/javascript/internal/RhinoJavaScriptEngine.java
@@ -28,8 +28,10 @@
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.scripting.SlingScriptHelper;
+import org.apache.sling.commons.classloader.DynamicClassLoader;
import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
import org.apache.sling.scripting.javascript.io.EspReader;
+import org.mozilla.javascript.ClassCache;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.JavaScriptException;
@@ -40,6 +42,7 @@
import org.mozilla.javascript.WrapFactory;
import org.mozilla.javascript.Wrapper;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A ScriptEngine that uses the Rhino interpreter to process Sling requests with
@@ -47,6 +50,8 @@
*/
public class RhinoJavaScriptEngine extends AbstractSlingScriptEngine {
+ private static final Logger LOGGER = LoggerFactory.getLogger(RhinoJavaScriptEngine.class);
+
private Scriptable rootScope;
public RhinoJavaScriptEngine(ScriptEngineFactory factory,
@@ -171,7 +176,22 @@
// if properties have been replaced, reset them
resetBoundProperties(scope, replacedProperties);
-
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ if (classLoader instanceof DynamicClassLoader) {
+ DynamicClassLoader dynamicClassLoader = (DynamicClassLoader) classLoader;
+ if (!dynamicClassLoader.isLive()) {
+ /**
+ * if the classloader on this thread is a dynamic class loader and it's dirty we should clear Rhino's class cache
+ * to avoid classloader leaks
+ */
+ if (scope != null) {
+ ClassCache classCache = ClassCache.get(scope);
+ classCache.clearCaches();
+ LOGGER.info("Detected dirty classloader on thread {}. Emptying Rhino's class cache.", Thread.currentThread()
+ .getName());
+ }
+ }
+ }
Context.exit();
}
}