You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2015/09/13 22:12:50 UTC

svn commit: r1702817 - in /jmeter/trunk: bin/jmeter.properties src/core/org/apache/jmeter/control/IfController.java xdocs/changes.xml

Author: pmouawad
Date: Sun Sep 13 20:12:47 2015
New Revision: 1702817

URL: http://svn.apache.org/r1702817
Log:
Bug 58406 - IfController : Use Nashorn Engine if available for JavaScript evaluation
Bugzilla Id: 58406

Modified:
    jmeter/trunk/bin/jmeter.properties
    jmeter/trunk/src/core/org/apache/jmeter/control/IfController.java
    jmeter/trunk/xdocs/changes.xml

Modified: jmeter/trunk/bin/jmeter.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/bin/jmeter.properties?rev=1702817&r1=1702816&r2=1702817&view=diff
==============================================================================
--- jmeter/trunk/bin/jmeter.properties (original)
+++ jmeter/trunk/bin/jmeter.properties Sun Sep 13 20:12:47 2015
@@ -1023,6 +1023,13 @@ beanshell.server.file=../extras/startup.
 # Default is true. Use false to revert to previous behaviour
 #CookieManager.check.cookies=true
 
+# Ability to revert to Rhino as default Javascript Engine used by IfController
+# JMeter works as following:
+# - JDK < 8 : Rhino
+# - JDK >= 8 : Nashorn
+# If you want to use Rhino on JDK8, set this property to true
+#ifcontroller.use_rhino=false
+
 # (2.0.3) JMeterThread behaviour has been changed to set the started flag before
 # the controllers are initialised. This is so controllers can access variables earlier. 
 # In case this causes problems, the previous behaviour can be restored by uncommenting

Modified: jmeter/trunk/src/core/org/apache/jmeter/control/IfController.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/control/IfController.java?rev=1702817&r1=1702816&r2=1702817&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/control/IfController.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/control/IfController.java Sun Sep 13 20:12:47 2015
@@ -20,8 +20,15 @@ package org.apache.jmeter.control;
 
 import java.io.Serializable;
 
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.SimpleScriptContext;
+
 import org.apache.jmeter.samplers.Sampler;
+import org.apache.jmeter.testelement.ThreadListener;
 import org.apache.jmeter.testelement.property.StringProperty;
+import org.apache.jmeter.util.JMeterUtils;
 import org.apache.jorphan.logging.LoggingManager;
 import org.apache.log.Logger;
 import org.mozilla.javascript.Context;
@@ -53,18 +60,92 @@ import org.mozilla.javascript.Scriptable
 
 // for unit test code @see TestIfController
 
-public class IfController extends GenericController implements Serializable {
+public class IfController extends GenericController implements Serializable, ThreadListener {
 
     private static final Logger logger = LoggingManager.getLoggerForClass();
 
-    private static final long serialVersionUID = 240L;
+    private static final long serialVersionUID = 241L;
 
     private static final String CONDITION = "IfController.condition"; //$NON-NLS-1$
 
     private static final String EVALUATE_ALL = "IfController.evaluateAll"; //$NON-NLS-1$
 
     private static final String USE_EXPRESSION = "IfController.useExpression"; //$NON-NLS-1$
+    
+    private static final String USE_RHINO_ENGINE_PROPERTY = "ifcontroller.use_rhino";
+
+    private static final boolean USE_RHINO_ENGINE = 
+            getInstance().getEngineByName("nashorn") == null || //$NON-NLS-1$
+            JMeterUtils.getPropDefault(USE_RHINO_ENGINE_PROPERTY, false) ;
 
+    
+    private static final ThreadLocal<ScriptEngine> NASHORN_ENGINE = new ThreadLocal<ScriptEngine>() {
+
+        /* (non-Javadoc)
+         * @see java.lang.ThreadLocal#initialValue()
+         */
+        @Override
+        protected ScriptEngine initialValue() {
+            return getInstance().getEngineByName("nashorn");//$NON-NLS-N$
+        }
+    
+    };
+
+    private interface JsEvaluator {
+        boolean evaluate(String testElementName, String condition);
+    }
+    
+    private static class RhinoJsEngine implements JsEvaluator {
+        @Override
+        public boolean evaluate(String testElementName, String condition) {
+            boolean result = false;
+            // now evaluate the condition using JavaScript
+            Context cx = Context.enter();
+            try {
+                Scriptable scope = cx.initStandardObjects(null);
+                Object cxResultObject = cx.evaluateString(scope, condition
+                /** * conditionString ** */
+                , "<cmd>", 1, null);
+                result = computeResultFromString(condition, Context.toString(cxResultObject));
+            } catch (Exception e) {
+                logger.error(testElementName+": error while processing "+ "[" + condition + "]\n", e);
+            } finally {
+                Context.exit();
+            }
+            return result;
+        }
+    }
+    
+    private static class NashornJsEngine implements JsEvaluator {
+        @Override
+        public boolean evaluate(String testElementName, String condition) {
+            try {
+                ScriptContext newContext = new SimpleScriptContext();
+                newContext.setBindings(NASHORN_ENGINE.get().createBindings(), ScriptContext.ENGINE_SCOPE);
+                Object o = NASHORN_ENGINE.get().eval(condition, newContext);
+                return computeResultFromString(condition, o.toString());
+            } catch (Exception ex) {
+                logger.error(testElementName+": error while processing "+ "[" + condition + "]\n", ex);
+            }
+            return false;
+        }
+    }
+        
+    private static JsEvaluator JAVASCRIPT_EVALUATOR = USE_RHINO_ENGINE ? new RhinoJsEngine() : new NashornJsEngine();
+    
+    /**
+     * Initialization On Demand Holder pattern
+     */
+    private static class LazyHolder {
+        public static final ScriptEngineManager INSTANCE = new ScriptEngineManager();
+    }
+ 
+    /**
+     * @return ScriptEngineManager singleton
+     */
+    public static ScriptEngineManager getInstance() {
+            return LazyHolder.INSTANCE;
+    }
     /**
      * constructor
      */
@@ -101,38 +182,37 @@ public class IfController extends Generi
      * evaluate the condition clause log error if bad condition
      */
     private boolean evaluateCondition(String cond) {
-        logger.debug("    getCondition() : [" + cond + "]");
-
-        String resultStr = "";
-        boolean result = false;
-
-        // now evaluate the condition using JavaScript
-        Context cx = Context.enter();
-        try {
-            Scriptable scope = cx.initStandardObjects(null);
-            Object cxResultObject = cx.evaluateString(scope, cond
-            /** * conditionString ** */
-            , "<cmd>", 1, null);
-            resultStr = Context.toString(cxResultObject);
-
-            if (resultStr.equals("false")) { //$NON-NLS-1$
-                result = false;
-            } else if (resultStr.equals("true")) { //$NON-NLS-1$
-                result = true;
-            } else {
-                throw new Exception(" BAD CONDITION :: " + cond + " :: expected true or false");
-            }
-
-            logger.debug("    >> evaluate Condition -  [ " + cond + "] results is  [" + result + "]");
-        } catch (Exception e) {
-            logger.error(getName()+": error while processing "+ "[" + cond + "]\n", e);
-        } finally {
-            Context.exit();
+        if(logger.isDebugEnabled()) {
+            logger.debug("    getCondition() : [" + cond + "]");
         }
+        return JAVASCRIPT_EVALUATOR.evaluate(getName(), cond);
+    }
 
+    /**
+     * @param condition
+     * @param resultStr
+     * @return boolean
+     * @throws Exception
+     */
+    private static final boolean computeResultFromString(String condition, String resultStr) throws Exception {
+        boolean result;
+        switch(resultStr) {
+            case "false":
+                result=false;
+                break;
+            case "true":
+                result=true;
+                break;
+            default:
+                throw new Exception(" BAD CONDITION :: " + condition + " :: expected true or false");
+        }
+        if(logger.isDebugEnabled()) {
+            logger.debug("    >> evaluate Condition -  [ " + condition + "] results is  [" + result + "]");
+        }
         return result;
     }
-
+    
+    
     private static boolean evaluateExpression(String cond) {
         return cond.equalsIgnoreCase("true"); // $NON-NLS-1$
     }
@@ -209,4 +289,12 @@ public class IfController extends Generi
     public void setUseExpression(boolean selected) {
         setProperty(USE_EXPRESSION, selected, false);
     }
+    @Override
+    public void threadStarted() {
+        
+    }
+    @Override
+    public void threadFinished() {
+       NASHORN_ENGINE.remove();
+    }
 }

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1702817&r1=1702816&r2=1702817&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml (original)
+++ jmeter/trunk/xdocs/changes.xml Sun Sep 13 20:12:47 2015
@@ -74,6 +74,7 @@ Summary
 
 <ul>
     <li>In RandomTimer class, protected instance timer has been replaced by getTimer() protected method, this is related to <bugzilla>58100</bugzilla>. This may impact 3rd party plugins.</li>
+    <li>If Controller will now use by default Nashorn Engine under Java8. If you want to revert to Rhino Engine, use property <code>ifcontroller.use_rhino=true</code>, see <bugzilla>58406</bugzilla></li>
 </ul>
 
 <!-- =================== Improvements =================== -->
@@ -94,6 +95,7 @@ Summary
 
 <h3>Controllers</h3>
 <ul>
+    <li><bug>58406</bug>IfController : Use Nashorn Engine if available for JavaScript evaluation</li>
 </ul>
 
 <h3>Listeners</h3>