/* * Copyright 2008-2011 the original author or authors. * * Licensed 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.mozilla.javascript; import static com.nominanuda.zen.oio.OioUtils.IO; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.UndeclaredThrowableException; import java.net.URL; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; import org.mozilla.javascript.tools.ToolErrorReporter; import com.nominanuda.zen.common.Check; @ThreadSafe public class RhinoHelper { public static final RhinoHelper RHINO = new RhinoHelper(); private final static String[] TOP_JAVA_NAMES = { "Packages", "java", "javax", "org", "com", "edu", "net" }; protected Object securityDomain; public ScriptableObject protocloneScriptable(Context cx, Scriptable scope) { ScriptableObject res = new NativeObject(); res.setPrototype(scope); res.setParentScope(null); return res; } public ScriptableObject createTopScope(Context cx, boolean allowJavaPackageAccess) throws Exception {//TODO more fine grained IOEx + some other ScriptableObject root; if(allowJavaPackageAccess) { root = new ImporterTopLevel(cx); } else { root = new NativeObject(); ScriptRuntime.initStandardObjects(cx, root, false); disallowJavaPackagesAccess(root); } return root; } private void disallowJavaPackagesAccess(ScriptableObject root) { for(String topJavaName : TOP_JAVA_NAMES) { ScriptableObject.deleteProperty(root, topJavaName); } } public void defineClassInScope(Scriptable scope, Class<? extends Scriptable> clazz) throws UndeclaredThrowableException { try { ScriptableObject.defineClass(scope, clazz); } catch (IllegalAccessException e) { throw new UndeclaredThrowableException(e); } catch (InstantiationException e) { throw new UndeclaredThrowableException(e); } catch (InvocationTargetException e) { throw new UndeclaredThrowableException(e); } } public Script compileScript(Reader r, String fileName, Object securityDomain, Context cx) throws EvaluatorException { try { return cx.compileReader(r, fileName, 1, securityDomain); } catch (EvaluatorException e) { throw Context.reportRuntimeError(e.getMessage()); } catch (IOException e) { throw Context.reportRuntimeError(e.getMessage()); } finally { try { r.close(); } catch (IOException e) { throw new RuntimeException(e); } } /* catch (RhinoException e) { ToolErrorReporter.reportException(cx.getErrorReporter(), e); throw Context.reportRuntimeError(e.getMessage()); } catch (VirtualMachineError ex) { String msg = ToolErrorReporter.getMessage("msg.uncaughtJSException", ex.toString()); throw Context.reportRuntimeError(msg); }*/ } public Object evaluateScript(Script script, Context cx, Scriptable scope) throws EvaluatorException { try { return script.exec(cx, scope); } catch (RhinoException e) { throw e;//TODO new WrappedRhinoException(e); } catch (VirtualMachineError e) { String msg = ToolErrorReporter.getMessage( "msg.uncaughtJSException", e.getMessage()); throw Context.reportRuntimeError(msg); } } public Object evaluateScriptWithContinuations(Script script, Context cx, Scriptable scope) throws EvaluatorException { try { cx.setOptimizationLevel(-1); return cx.executeScriptWithContinuations(script, scope); } catch (RhinoException e) { throw e;//TODO new WrappedRhinoException(e); } catch (VirtualMachineError e) { String msg = ToolErrorReporter.getMessage( "msg.uncaughtJSException", e.getMessage()); throw Context.reportRuntimeError(msg); } } //TODO public Script instantiate(Class<? extends Script> clazz, Context cx) throws EvaluatorException { try { GeneratedClassLoader loader = SecurityController.createLoader( cx.getApplicationClassLoader(), securityDomain); loader.linkClass(clazz); if (!Script.class.isAssignableFrom(clazz)) { throw Context.reportRuntimeError("msg.must.implement.Script"); } return clazz.newInstance(); } catch (InstantiationException e) { Context.reportError(e.getMessage()); throw Context.reportRuntimeError(e.getMessage()); } catch (IllegalAccessException e) { Context.reportError(e.getMessage()); throw Context.reportRuntimeError(e.getMessage()); } /*} catch (RhinoException e) { ToolErrorReporter.reportException(cx.getErrorReporter(), e); throw Context.reportRuntimeError(e.getMessage()); */ } protected Object getSecurityDomain() { return securityDomain; } public void setSecurityDomain(Object securityDomain) { this.securityDomain = securityDomain; } public Object evaluateURL(Context cx, URL url, Scriptable scope) throws IOException { Reader r = new InputStreamReader(url.openStream(), "UTF-8");///TODO detect charset if possible return evaluateReader(cx, r, url.toString(), scope); } public Object evaluateReader(Context cx, Reader src, String path, Scriptable scope) { //TODO should throw exceptions.. boolean allowContinuations = false; // try { // URI u = new URI(scriptName); // if(u.isAbsolute()) { // scope.put(INCUDE_BASE, scope, u); // } // } catch(Exception e) {} Script script = compileScript(src, path, /*TODO*/null, cx); return allowContinuations ? evaluateScriptWithContinuations(script, cx, scope) : evaluateScript(script, cx, scope); } public Scriptable newObject(Context cx, Scriptable contructorSearchScope) { return cx.newObject(contructorSearchScope); } public Scriptable newArray(Context cx, Scriptable contructorSearchScope) { return cx.newArray(contructorSearchScope, 0); } public boolean isArray(Object o) { return ScriptRuntime.isArrayObject(o); } //TODO WRONG !!!!!!! call (Callable) e basta!! public Object callFunctionInScope(Context cx, Scriptable scope, String functionName, Object[] args) { return callFunctionInScope(cx, scope, functionName, args, false); } public Object callFunctionInScopeWithContinuations(Context cx, Scriptable scope, String functionName, Object[] args) throws ContinuationPending { return callFunctionInScope(cx, scope, functionName, args, true); } protected Object callFunctionInScope(Context cx, Scriptable scope, String functionName, Object[] args, boolean allowContinuations) { if(args == null) { args = new Object[0]; } Object f = scope.get(functionName, scope); if (f == null || !(f instanceof Function)) { throw new IllegalArgumentException("Cannot find function " + functionName+" in provided scope"); } Function fun = (Function)f; Object res = allowContinuations ? cx.callFunctionWithContinuations(fun, scope, args) : fun.call(cx, scope, scope, args); return res; } public Map<String, Function> findFunctionsInScope(Scriptable scope) { Map<String, Function> res = new LinkedHashMap<String, Function>(); Object[] ids = scope.getIds(); for(Object id : ids) { if(id instanceof String) { Object var = scope.get((String)id, scope); if (var != null && var instanceof Function) { res.put((String)id, (Function)var); } } } return res; } public @Nullable Function findFunctionInScope(Scriptable scope, String name) { Object[] ids = scope.getIds(); for(Object id : ids) { if(id.equals(name)) { Object var = scope.get((String)id, scope); if (var != null && var instanceof Function) { return (Function)var; } } } return null; } public Scriptable jsonToScriptable(Context cx, Reader json) { Reader r = IO.concat( new StringReader("(function(){return "), json, new StringReader("})();")); return (Scriptable)evaluateReader(cx, r, " - ", scopeFactory.createInContext(cx)); } private ScopeFactory scopeFactory = new ScopeFactory(); // public Object[] nativeArrayToJavaArray(NativeArray arr) { // List<Object> l = new LinkedList<Object>(); // for(int i = 0, len=(int)arr.getLength(); i < len; i++) { // l.add(i, arr.get(i, arr)); // } // return l.toArray(new Object[l.size()]); // } // public void putOrAppendProp(Scriptable obj, String pName, Object pVal) { // if(obj.has(pName, obj)) { // Object val = obj.get(pName, obj); // if(isArray(val)) { // NativeArray arr = (NativeArray)val; // int last = (int)arr.getLength(); // arr.put(last, arr, pVal); // } else { // Scriptable arr = newArray(obj); // arr.put(0, arr, val); // arr.put(1, arr, pVal); // obj.put(pName, obj, arr); // } // } else { // obj.put(pName, obj, pVal); // } // } public Object getProperty(Scriptable obj, Object index) { index = validateIndex(index); return index instanceof String ? ScriptableObject.getProperty(obj, (String)index) : ScriptableObject.getProperty(obj, ((Number)index).intValue()); } public Object deleteProperty(Scriptable obj, Object index) { index = validateIndex(index); return index instanceof String ? ScriptableObject.deleteProperty(obj, (String)index) : ScriptableObject.deleteProperty(obj, ((Number)index).intValue()); } public void putProperty(Scriptable obj, Object index, Object value) { index = validateIndex(index); if (index instanceof String) { ScriptableObject.putProperty(obj, (String)index, value); } else { ScriptableObject.putProperty(obj, ((Number)index).intValue(), value); } } private Object validateIndex(Object index) { Check.notNull(index); if (index instanceof String) { final String s = (String)index; final int l = s.length(); if (l > 0) { for (int i = 0; i < l; i++) { char c = s.charAt(i); if (c < '0' || c > '9') { return s; } } return Integer.parseInt(s); } } return index; } public <T extends Scriptable> BaseFunction buildClassCtor(Scriptable scope, Class<T> clazz,boolean sealed,boolean mapInheritance) throws IllegalAccessException, InstantiationException,InvocationTargetException{ return ScriptableObject.buildClassCtor(scope, clazz, sealed, mapInheritance); } public boolean isUndefined(Object val) { return Undefined.instance == val; } }