Repository: logging-log4j2
Updated Branches:
  refs/heads/master 361785ab7 -> 2d18d39ca


[LOG4J2-1578] RoutingAppender can be configured with scripts. 

Don't share a Bindings object accross script invocations. Instead,
create a new Bindings objects and share ConcurrentMap for the scripts
static variables.

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/2d18d39c
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/2d18d39c
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/2d18d39c

Branch: refs/heads/master
Commit: 2d18d39caa141cba00eca3b46931f79fb9d2186d
Parents: 361785a
Author: Gary Gregory <[email protected]>
Authored: Wed Sep 14 18:53:15 2016 -0700
Committer: Gary Gregory <[email protected]>
Committed: Wed Sep 14 18:53:15 2016 -0700

----------------------------------------------------------------------
 .../log4j/core/appender/routing/Routes.java     |  23 +-
 .../core/appender/routing/RoutingAppender.java  |  14 +-
 .../log4j/core/script/ScriptManager.java        | 559 ++++++++++---------
 .../routing/DefaultRouteScriptAppenderTest.java |   9 +-
 .../routing/RoutesScriptAppenderTest.java       |  47 +-
 5 files changed, 338 insertions(+), 314 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2d18d39c/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
index 0fbbdc4..bf3ccef 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/Routes.java
@@ -16,7 +16,10 @@
  */
 package org.apache.logging.log4j.core.appender.routing;
 
+import static 
org.apache.logging.log4j.core.appender.routing.RoutingAppender.STATIC_VARIABLES_KEY;
+
 import java.util.Objects;
+import java.util.concurrent.ConcurrentMap;
 
 import javax.script.Bindings;
 
@@ -138,8 +141,6 @@ public final class Routes {
         return new Builder();
     }
     
-    private Bindings bindings;
-    
     private final Configuration configuration;
     
     private final String pattern;
@@ -148,7 +149,7 @@ public final class Routes {
     
     // TODO Why not make this a Map or add a Map.
     private final Route[] routes;
-
+    
     private Routes(final Configuration configuration, final AbstractScript 
patternScript, final String pattern, final Route... routes) {
         this.configuration = configuration;
         this.patternScript = patternScript;
@@ -156,21 +157,17 @@ public final class Routes {
         this.routes = routes;
     }
 
-    public Bindings getBindings() {
-        return bindings;
-    }
-
     /**
      * Returns the pattern.
      * @param event The log event passed to the script (if there is a script.)
+     * @param scriptStaticVariables The script's static variables.
      * @return the pattern.
      */
-    public String getPattern(final LogEvent event) {
+    public String getPattern(final LogEvent event, ConcurrentMap<Object, 
Object> scriptStaticVariables) {
         if (patternScript != null) {
             final ScriptManager scriptManager = 
configuration.getScriptManager();
-            if (bindings == null) {
-                bindings = scriptManager.createBindings(patternScript);
-            }
+            final Bindings bindings = 
scriptManager.createBindings(patternScript);
+            bindings.put(STATIC_VARIABLES_KEY, scriptStaticVariables);
             bindings.put(LOG_EVENT_KEY, event);
             final Object object = 
scriptManager.execute(patternScript.getName(), bindings);
             bindings.remove(LOG_EVENT_KEY);
@@ -204,10 +201,6 @@ public final class Routes {
         return routes;
     }
 
-    public void setBindings(final Bindings bindings) {
-        this.bindings = bindings;
-    }
-
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("{");

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2d18d39c/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
index e823484..49cc600 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
@@ -52,6 +52,8 @@ import org.apache.logging.log4j.core.util.Booleans;
 @Plugin(name = "Routing", category = "Core", elementType = "appender", 
printObject = true)
 public final class RoutingAppender extends AbstractAppender {
     
+    public static final String STATIC_VARIABLES_KEY = "staticVariables";
+
     public static class Builder<B extends Builder<B>> extends 
AbstractAppender.Builder<B>
             implements 
org.apache.logging.log4j.core.util.Builder<RoutingAppender> {
                 
@@ -146,7 +148,7 @@ public final class RoutingAppender extends AbstractAppender 
{
     private final RewritePolicy rewritePolicy;
     private final PurgePolicy purgePolicy;
     private final AbstractScript defaultRouteScript;
-    private Bindings bindings;
+    private final ConcurrentMap<Object, Object> scriptStaticVariables = new 
ConcurrentHashMap<>();
     
     private RoutingAppender(final String name, final Filter filter, final 
boolean ignoreExceptions, final Routes routes,
             final RewritePolicy rewritePolicy, final Configuration 
configuration, final PurgePolicy purgePolicy,
@@ -181,8 +183,8 @@ public final class RoutingAppender extends AbstractAppender 
{
             } else {
                 final ScriptManager scriptManager = 
configuration.getScriptManager();
                 scriptManager.addScript(defaultRouteScript);
-                bindings = scriptManager.createBindings(defaultRouteScript);
-                routes.setBindings(bindings);
+                final Bindings bindings = 
scriptManager.createBindings(defaultRouteScript);
+                bindings.put(STATIC_VARIABLES_KEY, scriptStaticVariables);
                 final Object object = 
scriptManager.execute(defaultRouteScript.getName(), bindings);
                 final Route route = routes.getRoute(Objects.toString(object, 
null));
                 if (route != null) {
@@ -225,7 +227,7 @@ public final class RoutingAppender extends AbstractAppender 
{
         if (rewritePolicy != null) {
             event = rewritePolicy.rewrite(event);
         }
-        final String pattern = routes.getPattern(event);
+        final String pattern = routes.getPattern(event, scriptStaticVariables);
         final String key = pattern != null ? 
configuration.getStrSubstitutor().replace(event, pattern) : 
defaultRoute.getKey();
         final AppenderControl control = getControl(key, event);
         if (control != null) {
@@ -365,7 +367,7 @@ public final class RoutingAppender extends AbstractAppender 
{
         return configuration;
     }
 
-    public Bindings getBindings() {
-        return bindings;
+    public ConcurrentMap<Object, Object> getScriptStaticVariables() {
+        return scriptStaticVariables;
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2d18d39c/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java
index ccb7993..3e274c9 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/script/ScriptManager.java
@@ -1,279 +1,280 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.core.script;
-
-import java.io.File;
-import java.io.Serializable;
-import java.nio.file.Path;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import javax.script.Bindings;
-import javax.script.Compilable;
-import javax.script.CompiledScript;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-import javax.script.SimpleBindings;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.util.FileWatcher;
-import org.apache.logging.log4j.core.util.WatchManager;
-import org.apache.logging.log4j.status.StatusLogger;
-
-/**
- * Manages the scripts use by the Configuration.
- */
-public class ScriptManager implements FileWatcher, Serializable {
-    
-    private abstract class AbstractScriptRunner implements ScriptRunner {
-        private final ConcurrentMap<Object, Object> scriptStaticVariables = 
new ConcurrentHashMap<>();
-        
-        @Override
-        public Bindings createBindings() {
-            final SimpleBindings bindings = new SimpleBindings();
-            bindings.put("configuration", configuration);
-            bindings.put("statusLogger", logger);
-            bindings.put("staticVariables", scriptStaticVariables);
-            return bindings;
-        }
-
-    }
-
-    private static final long serialVersionUID = -2534169384971965196L;
-    private static final String KEY_THREADING = "THREADING";
-    private static final Logger logger = StatusLogger.getLogger();
-    
-    private final Configuration configuration;
-    private final ScriptEngineManager manager = new ScriptEngineManager();
-    private final ConcurrentMap<String, ScriptRunner> scriptRunners = new 
ConcurrentHashMap<>();
-    private final String languages;
-    private final WatchManager watchManager;
-
-    public ScriptManager(final Configuration configuration, final WatchManager 
watchManager) {
-        this.configuration = configuration;
-        this.watchManager = watchManager;
-        final List<ScriptEngineFactory> factories = 
manager.getEngineFactories();
-        if (logger.isDebugEnabled()) {
-            final StringBuilder sb = new StringBuilder();
-            logger.debug("Installed script engines");
-            for (final ScriptEngineFactory factory : factories) {
-                String threading = (String) 
factory.getParameter(KEY_THREADING);
-                if (threading == null) {
-                    threading = "Not Thread Safe";
-                }
-                final StringBuilder names = new StringBuilder();
-                for (final String name : factory.getNames()) {
-                    if (names.length() > 0) {
-                        names.append(", ");
-                    }
-                    names.append(name);
-                }
-                if (sb.length() > 0) {
-                    sb.append(", ");
-                }
-                sb.append(names);
-                final boolean compiled = factory.getScriptEngine() instanceof 
Compilable;
-                logger.debug(factory.getEngineName() + " Version: " + 
factory.getEngineVersion() +
-                    ", Language: " + factory.getLanguageName() + ", Threading: 
" + threading +
-                    ", Compile: " + compiled + ", Names: {" + names.toString() 
+ "}");
-            }
-            languages = sb.toString();
-        } else {
-            final StringBuilder names = new StringBuilder();
-            for (final ScriptEngineFactory factory : factories) {
-                for (final String name : factory.getNames()) {
-                    if (names.length() > 0) {
-                        names.append(", ");
-                    }
-                    names.append(name);
-                }
-            }
-            languages = names.toString();
-        }
-    }
-
-    public void addScript(final AbstractScript script) {
-        final ScriptEngine engine = 
manager.getEngineByName(script.getLanguage());
-        if (engine == null) {
-            logger.error("No ScriptEngine found for language " + 
script.getLanguage() + ". Available languages are: " +
-                    languages);
-            return;
-        }
-        if (engine.getFactory().getParameter(KEY_THREADING) == null) {
-            scriptRunners.put(script.getName(), new 
ThreadLocalScriptRunner(script));
-        } else {
-            scriptRunners.put(script.getName(), new MainScriptRunner(engine, 
script));
-        }
-
-        if (script instanceof ScriptFile) {
-            final ScriptFile scriptFile = (ScriptFile) script;
-            final Path path = scriptFile.getPath();
-            if (scriptFile.isWatched() && path != null) {
-                watchManager.watchFile(path.toFile(), this);
-            }
-        }
-    }
-
-    public Bindings createBindings(AbstractScript script) {
-        return getScriptRunner(script).createBindings();
-    }
-
-    public AbstractScript getScript(final String name) {
-        final ScriptRunner runner = scriptRunners.get(name);
-        return runner != null ? runner.getScript() : null;
-    }
-
-    @Override
-    public void fileModified(final File file) {
-        final ScriptRunner runner = scriptRunners.get(file.toString());
-        if (runner == null) {
-            logger.info("{} is not a running script");
-            return;
-        }
-        final ScriptEngine engine = runner.getScriptEngine();
-        final AbstractScript script = runner.getScript();
-        if (engine.getFactory().getParameter(KEY_THREADING) == null) {
-            scriptRunners.put(script.getName(), new 
ThreadLocalScriptRunner(script));
-        } else {
-            scriptRunners.put(script.getName(), new MainScriptRunner(engine, 
script));
-        }
-
-    }
-
-    public Object execute(final String name, final Bindings bindings) {
-        final ScriptRunner scriptRunner = scriptRunners.get(name);
-        if (scriptRunner == null) {
-            logger.warn("No script named {} could be found");
-            return null;
-        }
-        return AccessController.doPrivileged(new PrivilegedAction<Object>() {
-            @Override
-            public Object run() {
-                return scriptRunner.execute(bindings);
-            }
-        });
-    }
-
-    private interface ScriptRunner {
-
-        Bindings createBindings();
-        
-        Object execute(Bindings bindings);
-
-        AbstractScript getScript();
-
-        ScriptEngine getScriptEngine();
-    }
-
-    private class MainScriptRunner extends AbstractScriptRunner {
-        private final AbstractScript script;
-        private final CompiledScript compiledScript;
-        private final ScriptEngine scriptEngine;
-
-        public MainScriptRunner(final ScriptEngine scriptEngine, final 
AbstractScript script) {
-            this.script = script;
-            this.scriptEngine = scriptEngine;
-            CompiledScript compiled = null;
-            if (scriptEngine instanceof Compilable) {
-                logger.debug("Script {} is compilable", script.getName());
-                compiled = AccessController.doPrivileged(new 
PrivilegedAction<CompiledScript>() {
-                    @Override
-                    public CompiledScript run() {
-                        try {
-                            return ((Compilable) 
scriptEngine).compile(script.getScriptText());
-                        } catch (final Throwable ex) {
-                                /* ScriptException is what really should be 
caught here. However, beanshell's
-                                 * ScriptEngine implements Compilable but then 
throws Error when the compile method
-                                 * is called!
-                                 */
-                            logger.warn("Error compiling script", ex);
-                            return null;
-                        }
-                    }
-                });
-            }
-            compiledScript = compiled;
-        }
-
-        @Override
-        public ScriptEngine getScriptEngine() {
-            return this.scriptEngine;
-        }
-
-        @Override
-        public Object execute(final Bindings bindings) {
-            if (compiledScript != null) {
-                try {
-                    return compiledScript.eval(bindings);
-                } catch (final ScriptException ex) {
-                    logger.error("Error running script " + script.getName(), 
ex);
-                    return null;
-                }
-            }
-            try {
-                return scriptEngine.eval(script.getScriptText(), bindings);
-            }   catch (final ScriptException ex) {
-                logger.error("Error running script " + script.getName(), ex);
-                return null;
-            }
-        }
-
-        @Override
-        public AbstractScript getScript() {
-            return script;
-        }
-    }
-
-    private class ThreadLocalScriptRunner extends AbstractScriptRunner {
-        private final AbstractScript script;
-
-        private final ThreadLocal<MainScriptRunner> runners = new 
ThreadLocal<MainScriptRunner>() {
-            @Override protected MainScriptRunner initialValue() {
-                final ScriptEngine engine = 
manager.getEngineByName(script.getLanguage());
-                return new MainScriptRunner(engine, script);
-            }
-        };
-
-        public ThreadLocalScriptRunner(final AbstractScript script) {
-            this.script = script;
-        }
-
-        @Override
-        public Object execute(final Bindings bindings) {
-            return runners.get().execute(bindings);
-        }
-
-        @Override
-        public AbstractScript getScript() {
-            return script;
-        }
-       @Override
-        public ScriptEngine getScriptEngine() {
-            return runners.get().getScriptEngine();
-        }
-    }
-
-    private ScriptRunner getScriptRunner(AbstractScript script) {
-        return scriptRunners.get(script.getName());
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.script;
+
+import java.io.File;
+import java.io.Serializable;
+import java.nio.file.Path;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.script.Bindings;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.util.FileWatcher;
+import org.apache.logging.log4j.core.util.WatchManager;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * Manages the scripts use by the Configuration.
+ */
+public class ScriptManager implements FileWatcher, Serializable {
+    
+    private abstract class AbstractScriptRunner implements ScriptRunner {
+        
+        private static final String KEY_STATUS_LOGGER = "statusLogger";
+        private static final String KEY_CONFIGURATION = "configuration";
+        
+        @Override
+        public Bindings createBindings() {
+            final SimpleBindings bindings = new SimpleBindings();
+            bindings.put(KEY_CONFIGURATION, configuration);
+            bindings.put(KEY_STATUS_LOGGER, logger);
+            return bindings;
+        }
+
+    }
+
+    private static final long serialVersionUID = -2534169384971965196L;
+    private static final String KEY_THREADING = "THREADING";
+    private static final Logger logger = StatusLogger.getLogger();
+    
+    private final Configuration configuration;
+    private final ScriptEngineManager manager = new ScriptEngineManager();
+    private final ConcurrentMap<String, ScriptRunner> scriptRunners = new 
ConcurrentHashMap<>();
+    private final String languages;
+    private final WatchManager watchManager;
+
+    public ScriptManager(final Configuration configuration, final WatchManager 
watchManager) {
+        this.configuration = configuration;
+        this.watchManager = watchManager;
+        final List<ScriptEngineFactory> factories = 
manager.getEngineFactories();
+        if (logger.isDebugEnabled()) {
+            final StringBuilder sb = new StringBuilder();
+            logger.debug("Installed script engines");
+            for (final ScriptEngineFactory factory : factories) {
+                String threading = (String) 
factory.getParameter(KEY_THREADING);
+                if (threading == null) {
+                    threading = "Not Thread Safe";
+                }
+                final StringBuilder names = new StringBuilder();
+                for (final String name : factory.getNames()) {
+                    if (names.length() > 0) {
+                        names.append(", ");
+                    }
+                    names.append(name);
+                }
+                if (sb.length() > 0) {
+                    sb.append(", ");
+                }
+                sb.append(names);
+                final boolean compiled = factory.getScriptEngine() instanceof 
Compilable;
+                logger.debug(factory.getEngineName() + " Version: " + 
factory.getEngineVersion() +
+                    ", Language: " + factory.getLanguageName() + ", Threading: 
" + threading +
+                    ", Compile: " + compiled + ", Names: {" + names.toString() 
+ "}");
+            }
+            languages = sb.toString();
+        } else {
+            final StringBuilder names = new StringBuilder();
+            for (final ScriptEngineFactory factory : factories) {
+                for (final String name : factory.getNames()) {
+                    if (names.length() > 0) {
+                        names.append(", ");
+                    }
+                    names.append(name);
+                }
+            }
+            languages = names.toString();
+        }
+    }
+
+    public void addScript(final AbstractScript script) {
+        final ScriptEngine engine = 
manager.getEngineByName(script.getLanguage());
+        if (engine == null) {
+            logger.error("No ScriptEngine found for language " + 
script.getLanguage() + ". Available languages are: " +
+                    languages);
+            return;
+        }
+        if (engine.getFactory().getParameter(KEY_THREADING) == null) {
+            scriptRunners.put(script.getName(), new 
ThreadLocalScriptRunner(script));
+        } else {
+            scriptRunners.put(script.getName(), new MainScriptRunner(engine, 
script));
+        }
+
+        if (script instanceof ScriptFile) {
+            final ScriptFile scriptFile = (ScriptFile) script;
+            final Path path = scriptFile.getPath();
+            if (scriptFile.isWatched() && path != null) {
+                watchManager.watchFile(path.toFile(), this);
+            }
+        }
+    }
+
+    public Bindings createBindings(AbstractScript script) {
+        return getScriptRunner(script).createBindings();
+    }
+
+    public AbstractScript getScript(final String name) {
+        final ScriptRunner runner = scriptRunners.get(name);
+        return runner != null ? runner.getScript() : null;
+    }
+
+    @Override
+    public void fileModified(final File file) {
+        final ScriptRunner runner = scriptRunners.get(file.toString());
+        if (runner == null) {
+            logger.info("{} is not a running script");
+            return;
+        }
+        final ScriptEngine engine = runner.getScriptEngine();
+        final AbstractScript script = runner.getScript();
+        if (engine.getFactory().getParameter(KEY_THREADING) == null) {
+            scriptRunners.put(script.getName(), new 
ThreadLocalScriptRunner(script));
+        } else {
+            scriptRunners.put(script.getName(), new MainScriptRunner(engine, 
script));
+        }
+
+    }
+
+    public Object execute(final String name, final Bindings bindings) {
+        final ScriptRunner scriptRunner = scriptRunners.get(name);
+        if (scriptRunner == null) {
+            logger.warn("No script named {} could be found");
+            return null;
+        }
+        return AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                return scriptRunner.execute(bindings);
+            }
+        });
+    }
+
+    private interface ScriptRunner {
+
+        Bindings createBindings();
+        
+        Object execute(Bindings bindings);
+
+        AbstractScript getScript();
+
+        ScriptEngine getScriptEngine();
+    }
+
+    private class MainScriptRunner extends AbstractScriptRunner {
+        private final AbstractScript script;
+        private final CompiledScript compiledScript;
+        private final ScriptEngine scriptEngine;
+
+        public MainScriptRunner(final ScriptEngine scriptEngine, final 
AbstractScript script) {
+            this.script = script;
+            this.scriptEngine = scriptEngine;
+            CompiledScript compiled = null;
+            if (scriptEngine instanceof Compilable) {
+                logger.debug("Script {} is compilable", script.getName());
+                compiled = AccessController.doPrivileged(new 
PrivilegedAction<CompiledScript>() {
+                    @Override
+                    public CompiledScript run() {
+                        try {
+                            return ((Compilable) 
scriptEngine).compile(script.getScriptText());
+                        } catch (final Throwable ex) {
+                                /* ScriptException is what really should be 
caught here. However, beanshell's
+                                 * ScriptEngine implements Compilable but then 
throws Error when the compile method
+                                 * is called!
+                                 */
+                            logger.warn("Error compiling script", ex);
+                            return null;
+                        }
+                    }
+                });
+            }
+            compiledScript = compiled;
+        }
+
+        @Override
+        public ScriptEngine getScriptEngine() {
+            return this.scriptEngine;
+        }
+
+        @Override
+        public Object execute(final Bindings bindings) {
+            if (compiledScript != null) {
+                try {
+                    return compiledScript.eval(bindings);
+                } catch (final ScriptException ex) {
+                    logger.error("Error running script " + script.getName(), 
ex);
+                    return null;
+                }
+            }
+            try {
+                return scriptEngine.eval(script.getScriptText(), bindings);
+            }   catch (final ScriptException ex) {
+                logger.error("Error running script " + script.getName(), ex);
+                return null;
+            }
+        }
+
+        @Override
+        public AbstractScript getScript() {
+            return script;
+        }
+    }
+
+    private class ThreadLocalScriptRunner extends AbstractScriptRunner {
+        private final AbstractScript script;
+
+        private final ThreadLocal<MainScriptRunner> runners = new 
ThreadLocal<MainScriptRunner>() {
+            @Override protected MainScriptRunner initialValue() {
+                final ScriptEngine engine = 
manager.getEngineByName(script.getLanguage());
+                return new MainScriptRunner(engine, script);
+            }
+        };
+
+        public ThreadLocalScriptRunner(final AbstractScript script) {
+            this.script = script;
+        }
+
+        @Override
+        public Object execute(final Bindings bindings) {
+            return runners.get().execute(bindings);
+        }
+
+        @Override
+        public AbstractScript getScript() {
+            return script;
+        }
+       @Override
+        public ScriptEngine getScriptEngine() {
+            return runners.get().getScriptEngine();
+        }
+    }
+
+    private ScriptRunner getScriptRunner(AbstractScript script) {
+        return scriptRunners.get(script.getName());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2d18d39c/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
index 670395b..b77d12f 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/DefaultRouteScriptAppenderTest.java
@@ -21,8 +21,7 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.List;
 import java.util.Map;
-
-import javax.script.Bindings;
+import java.util.concurrent.ConcurrentMap;
 
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.MarkerManager;
@@ -67,10 +66,10 @@ public class DefaultRouteScriptAppenderTest {
 
     private void checkStaticVars() {
         final RoutingAppender routingAppender = getRoutingAppender();
-        final Bindings bindings = routingAppender.getBindings();
+        final ConcurrentMap<Object, Object> map = 
routingAppender.getScriptStaticVariables();
         if (expectBindingEntries) {
-            Assert.assertEquals("TestValue2", ((Map<?, ?>) 
bindings.get("staticVariables")).get("TestKey"));
-            Assert.assertEquals("HEXDUMP", ((Map<?, ?>) 
bindings.get("staticVariables")).get("MarkerName"));
+            Assert.assertEquals("TestValue2", map.get("TestKey"));
+            Assert.assertEquals("HEXDUMP", map.get("MarkerName"));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2d18d39c/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java
index 84d13a1..7e40234 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/routing/RoutesScriptAppenderTest.java
@@ -21,10 +21,16 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.config.AppenderControl;
+import org.apache.logging.log4j.core.impl.DefaultLogEventFactory;
 import org.apache.logging.log4j.junit.LoggerContextRule;
 import org.apache.logging.log4j.test.appender.ListAppender;
 import org.junit.Assert;
@@ -39,20 +45,36 @@ import org.junit.runners.Parameterized;
 @RunWith(Parameterized.class)
 public class RoutesScriptAppenderTest {
 
-    @Parameterized.Parameters(name = "{0}")
-    public static String[] getParameters() {
-        return new String[] { 
-                "log4j-routing-routes-script-groovy.xml",
-                "log4j-routing-routes-script-javascript.xml" };
+    @Parameterized.Parameters(name = "{0} {1}")
+    public static Object[][] getParameters() {
+        // @formatter:off
+        return new Object[][] { 
+            { "log4j-routing-routes-script-groovy.xml", false },
+            { "log4j-routing-routes-script-javascript.xml", false },
+            { "log4j-routing-script-staticvars-javascript.xml", true },
+            { "log4j-routing-script-staticvars-groovy.xml", true },
+        };
+        // @formatter:on
     }
 
     @Rule
     public final LoggerContextRule loggerContextRule;
 
-    public RoutesScriptAppenderTest(final String configLocation) {
+    private final boolean expectBindingEntries;
+    
+    public RoutesScriptAppenderTest(final String configLocation, final boolean 
expectBindingEntries) {
         this.loggerContextRule = new LoggerContextRule(configLocation);
+        this.expectBindingEntries = expectBindingEntries;
     }
 
+    private void checkStaticVars() {
+        final RoutingAppender routingAppender = getRoutingAppender();
+        final ConcurrentMap<Object, Object> map = 
routingAppender.getScriptStaticVariables();
+        if (expectBindingEntries) {
+            Assert.assertEquals("TestValue2", map.get("TestKey"));
+            Assert.assertEquals("HEXDUMP", map.get("MarkerName"));
+        }
+    }
     private ListAppender getListAppender() {
         final String key = "Service2";
         final RoutingAppender routingAppender = getRoutingAppender();
@@ -69,6 +91,7 @@ public class RoutesScriptAppenderTest {
     }
 
     private void logAndCheck() {
+        Marker marker = MarkerManager.getMarker("HEXDUMP");
         final Logger logger = 
loggerContextRule.getLogger(RoutesScriptAppenderTest.class);
         logger.error("Hello");
         final ListAppender listAppender = getListAppender();
@@ -77,6 +100,8 @@ public class RoutesScriptAppenderTest {
         assertTrue("Incorrect number of events. Expected 1, got " + 
list.size(), list.size() == 1);
         logger.error("World");
         assertTrue("Incorrect number of events. Expected 2, got " + 
list.size(), list.size() == 2);
+        logger.error(marker, "DEADBEEF");
+        assertTrue("Incorrect number of events. Expected 3, got " + 
list.size(), list.size() == 3);
     }
 
     @Test(expected = AssertionError.class)
@@ -105,12 +130,14 @@ public class RoutesScriptAppenderTest {
     @Test
     public void testRoutingAppenderRoutes() {
         final RoutingAppender routingAppender = getRoutingAppender();
-        Assert.assertNull(routingAppender.getDefaultRouteScript());
-        Assert.assertNull(routingAppender.getDefaultRoute());
+        Assert.assertEquals(expectBindingEntries, 
routingAppender.getDefaultRouteScript() != null);
+        Assert.assertEquals(expectBindingEntries, 
routingAppender.getDefaultRoute() != null);
         final Routes routes = routingAppender.getRoutes();
         Assert.assertNotNull(routes);
         Assert.assertNotNull(routes.getPatternScript());
-        Assert.assertEquals("Service2", routes.getPattern(null));
+        final LogEvent logEvent = 
DefaultLogEventFactory.getInstance().createEvent("", null, "", Level.ERROR, 
null,
+                null, null);
+        Assert.assertEquals("Service2", routes.getPattern(logEvent, new 
ConcurrentHashMap<>()));
     }
 
     @Test
@@ -121,10 +148,12 @@ public class RoutesScriptAppenderTest {
     @Test
     public void testRoutingPresence1() {
         logAndCheck();
+        checkStaticVars();
     }
 
     @Test
     public void testRoutingPresence2() {
         logAndCheck();
+        checkStaticVars();
     }
 }

Reply via email to