Save This Page
Home » bsf-src-2.4.0 » org.apache.bsf.engines.javascript » [javadoc | source]
    1   /*
    2    * Copyright 2004,2004 The Apache Software Foundation.
    3    * 
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    * 
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    * 
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.apache.bsf.engines.javascript;
   18   
   19   import java.util.Iterator;
   20   import java.util.Vector;
   21   
   22   import org.apache.bsf.BSFDeclaredBean;
   23   import org.apache.bsf.BSFException;
   24   import org.apache.bsf.BSFManager;
   25   import org.apache.bsf.util.BSFEngineImpl;
   26   import org.apache.bsf.util.BSFFunctions;
   27   import org.mozilla.javascript.Context;
   28   import org.mozilla.javascript.EvaluatorException;
   29   import org.mozilla.javascript.Function;
   30   import org.mozilla.javascript.ImporterTopLevel;
   31   import org.mozilla.javascript.JavaScriptException;
   32   import org.mozilla.javascript.NativeJavaObject;
   33   import org.mozilla.javascript.Scriptable;
   34   import org.mozilla.javascript.WrappedException;
   35   import org.mozilla.javascript.Wrapper;
   36   
   37   /**
   38    * This is the interface to Netscape's Rhino (JavaScript) from the
   39    * Bean Scripting Framework.
   40    * <p>
   41    * The original version of this code was first written by Adam Peller
   42    * for use in LotusXSL. Sanjiva took his code and adapted it for BSF.
   43    *
   44    * @author   Adam Peller <peller@lotus.com>
   45    * @author   Sanjiva Weerawarana
   46    * @author   Matthew J. Duftler
   47    * @author   Norris Boyd
   48    */
   49   public class JavaScriptEngine extends BSFEngineImpl {
   50       /**
   51        * The global script object, where all embedded functions are defined,
   52        * as well as the standard ECMA "core" objects.
   53        */
   54       private Scriptable global;
   55   
   56       /**
   57        * Return an object from an extension.
   58        * @param object Object on which to make the call (ignored).
   59        * @param method The name of the method to call.
   60        * @param args an array of arguments to be
   61        * passed to the extension, which may be either
   62        * Vectors of Nodes, or Strings.
   63        */
   64       public Object call(Object object, String method, Object[] args)
   65           throws BSFException {
   66   
   67           Object retval = null;
   68           Context cx;
   69   
   70           try {
   71               cx = Context.enter();
   72   
   73               // REMIND: convert arg list Vectors here?
   74   
   75               Object fun = global.get(method, global);
   76               // NOTE: Source and line arguments are nonsense in a call().
   77               //       Any way to make these arguments *sensible?
   78               if (fun == Scriptable.NOT_FOUND)
   79                   throw new EvaluatorException("function " + method +
   80                                                " not found.", "none", 0);
   81   
   82               cx.setOptimizationLevel(-1);
   83               cx.setGeneratingDebug(false);
   84               cx.setGeneratingSource(false);
   85               cx.setOptimizationLevel(0);
   86               cx.setDebugger(null, null);
   87               
   88               retval =
   89                   ((Function) fun).call(cx, global, global, args);
   90               
   91   //                ScriptRuntime.call(cx, fun, global, args, global);
   92   
   93               if (retval instanceof Wrapper)
   94                   retval = ((Wrapper) retval).unwrap();
   95           } 
   96           catch (Throwable t) {
   97               handleError(t);
   98           } 
   99           finally {
  100               Context.exit();
  101           }
  102           return retval;
  103       }
  104   
  105       public void declareBean(BSFDeclaredBean bean) throws BSFException {
  106           if ((bean.bean instanceof Number) ||
  107               (bean.bean instanceof String) ||
  108               (bean.bean instanceof Boolean)) {
  109               global.put(bean.name, global, bean.bean);
  110           } 
  111           else {
  112               // Must wrap non-scriptable objects before presenting to Rhino
  113               Scriptable wrapped = Context.toObject(bean.bean, global);
  114               global.put(bean.name, global, wrapped);
  115           }
  116       }
  117   
  118       /**
  119        * This is used by an application to evaluate a string containing
  120        * some expression.
  121        */
  122       public Object eval(String source, int lineNo, int columnNo, Object oscript)
  123           throws BSFException {
  124   
  125           String scriptText = oscript.toString();
  126           Object retval = null;
  127           Context cx;
  128   
  129           try {
  130               cx = Context.enter();
  131   
  132               cx.setOptimizationLevel(-1);
  133               cx.setGeneratingDebug(false);
  134               cx.setGeneratingSource(false);
  135               cx.setOptimizationLevel(0);
  136               cx.setDebugger(null, null);
  137   
  138               retval = cx.evaluateString(global, scriptText,
  139                                          source, lineNo,
  140                                          null);
  141   
  142               if (retval instanceof NativeJavaObject)
  143                   retval = ((NativeJavaObject) retval).unwrap();
  144   
  145           } 
  146           catch (Throwable t) { // includes JavaScriptException, rethrows Errors
  147               handleError(t);
  148           } 
  149           finally {
  150               Context.exit();
  151           }
  152           return retval;
  153       }
  154   
  155       private void handleError(Throwable t) throws BSFException {
  156           if (t instanceof WrappedException)
  157               t = ((WrappedException) t).getWrappedException();
  158   
  159           String message = null;
  160           Throwable target = t;
  161   
  162           if (t instanceof JavaScriptException) {
  163               message = t.getLocalizedMessage();
  164   
  165               // Is it an exception wrapped in a JavaScriptException?
  166               Object value = ((JavaScriptException) t).getValue();
  167               if (value instanceof Throwable) {
  168                   // likely a wrapped exception from a LiveConnect call.
  169                   // Display its stack trace as a diagnostic
  170                   target = (Throwable) value;
  171               }
  172           }
  173           else if (t instanceof EvaluatorException ||
  174                    t instanceof SecurityException) {
  175               message = t.getLocalizedMessage();
  176           }
  177           else if (t instanceof RuntimeException) {
  178               message = "Internal Error: " + t.toString();
  179           }
  180           else if (t instanceof StackOverflowError) {
  181               message = "Stack Overflow";
  182           }
  183   
  184           if (message == null)
  185               message = t.toString();
  186   
  187           if (t instanceof Error && !(t instanceof StackOverflowError)) {
  188               // Re-throw Errors because we're supposed to let the JVM see it
  189               // Don't re-throw StackOverflows, because we know we've
  190               // corrected the situation by aborting the loop and
  191               // a long stacktrace would end up on the user's console
  192               throw (Error) t;
  193           }
  194           else {
  195               throw new BSFException(BSFException.REASON_OTHER_ERROR,
  196                                      "JavaScript Error: " + message,
  197                                      target);
  198           }
  199       }
  200   
  201       /**
  202        * Initialize the engine. 
  203        * Put the manager into the context-manager
  204        * map hashtable too.
  205        */
  206       public void initialize(BSFManager mgr, String lang, Vector declaredBeans)
  207           throws BSFException {
  208           
  209           super.initialize(mgr, lang, declaredBeans);
  210   
  211           // Initialize context and global scope object
  212           try {
  213               Context cx = Context.enter();
  214               global = new ImporterTopLevel(cx);
  215               Scriptable bsf = Context.toObject(new BSFFunctions(mgr, this), global);
  216               global.put("bsf", global, bsf);
  217   
  218               for(Iterator it = declaredBeans.iterator(); it.hasNext();) {
  219               	declareBean((BSFDeclaredBean) it.next());
  220               }
  221           } 
  222           catch (Throwable t) {
  223   
  224           } 
  225           finally {
  226               Context.exit();
  227           }
  228       }
  229   
  230       public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
  231           global.delete(bean.name);
  232       }
  233   }

Save This Page
Home » bsf-src-2.4.0 » org.apache.bsf.engines.javascript » [javadoc | source]