Showing the changes to java/pkg/com/sun/script/javascript (13 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,467 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package com.sun.script.javascript; | |
| 27 | +import sun.org.mozilla.javascript.internal.*; | |
| 28 | +import javax.script.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * ExternalScriptable is an implementation of Scriptable | |
| 33 | + * backed by a JSR 223 ScriptContext instance. | |
| 34 | + * | |
| 35 | + * @author Mike Grogan | |
| 36 | + * @author A. Sundararajan | |
| 37 | + * @since 1.6 | |
| 38 | + */ | |
| 39 | + | |
| 40 | +final class ExternalScriptable implements Scriptable { | |
| 41 | + /* Underlying ScriptContext that we use to store | |
| 42 | + * named variables of this scope. | |
| 43 | + */ | |
| 44 | + private ScriptContext context; | |
| 45 | + | |
| 46 | + /* JavaScript allows variables to be named as numbers (indexed | |
| 47 | + * properties). This way arrays, objects (scopes) are treated uniformly. | |
| 48 | + * Note that JSR 223 API supports only String named variables and | |
| 49 | + * so we can't store these in Bindings. Also, JavaScript allows name | |
| 50 | + * of the property name to be even empty String! Again, JSR 223 API | |
| 51 | + * does not support empty name. So, we use the following fallback map | |
| 52 | + * to store such variables of this scope. This map is not exposed to | |
| 53 | + * JSR 223 API. We can just script objects "as is" and need not convert. | |
| 54 | + */ | |
| 55 | + private Map<Object, Object> indexedProps; | |
| 56 | + | |
| 57 | + // my prototype | |
| 58 | + private Scriptable prototype; | |
| 59 | + // my parent scope, if any | |
| 60 | + private Scriptable parent; | |
| 61 | + | |
| 62 | + ExternalScriptable(ScriptContext context) { | |
| 63 | + this(context, new HashMap<Object, Object>()); | |
| 64 | + } | |
| 65 | + | |
| 66 | + ExternalScriptable(ScriptContext context, Map<Object, Object> indexedProps) { | |
| 67 | + if (context == null) { | |
| 68 | + throw new NullPointerException("context is null"); | |
| 69 | + } | |
| 70 | + this.context = context; | |
| 71 | + this.indexedProps = indexedProps; | |
| 72 | + } | |
| 73 | + | |
| 74 | + ScriptContext getContext() { | |
| 75 | + return context; | |
| 76 | + } | |
| 77 | + | |
| 78 | + private boolean isEmpty(String name) { | |
| 79 | + return name.equals(""); | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * Return the name of the class. | |
| 84 | + */ | |
| 85 | + public String getClassName() { | |
| 86 | + return "Global"; | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * Returns the value of the named property or NOT_FOUND. | |
| 91 | + * | |
| 92 | + * If the property was created using defineProperty, the | |
| 93 | + * appropriate getter method is called. | |
| 94 | + * | |
| 95 | + * @param name the name of the property | |
| 96 | + * @param start the object in which the lookup began | |
| 97 | + * @return the value of the property (may be null), or NOT_FOUND | |
| 98 | + */ | |
| 99 | + public synchronized Object get(String name, Scriptable start) { | |
| 100 | + if (isEmpty(name)) { | |
| 101 | + if (indexedProps.containsKey(name)) { | |
| 102 | + return indexedProps.get(name); | |
| 103 | + } else { | |
| 104 | + return NOT_FOUND; | |
| 105 | + } | |
| 106 | + } else { | |
| 107 | + synchronized (context) { | |
| 108 | + int scope = context.getAttributesScope(name); | |
| 109 | + if (scope != -1) { | |
| 110 | + Object value = context.getAttribute(name, scope); | |
| 111 | + return Context.javaToJS(value, this); | |
| 112 | + } else { | |
| 113 | + return NOT_FOUND; | |
| 114 | + } | |
| 115 | + } | |
| 116 | + } | |
| 117 | + } | |
| 118 | + | |
| 119 | + /** | |
| 120 | + * Returns the value of the indexed property or NOT_FOUND. | |
| 121 | + * | |
| 122 | + * @param index the numeric index for the property | |
| 123 | + * @param start the object in which the lookup began | |
| 124 | + * @return the value of the property (may be null), or NOT_FOUND | |
| 125 | + */ | |
| 126 | + public synchronized Object get(int index, Scriptable start) { | |
| 127 | + Integer key = new Integer(index); | |
| 128 | + if (indexedProps.containsKey(index)) { | |
| 129 | + return indexedProps.get(key); | |
| 130 | + } else { | |
| 131 | + return NOT_FOUND; | |
| 132 | + } | |
| 133 | + } | |
| 134 | + | |
| 135 | + /** | |
| 136 | + * Returns true if the named property is defined. | |
| 137 | + * | |
| 138 | + * @param name the name of the property | |
| 139 | + * @param start the object in which the lookup began | |
| 140 | + * @return true if and only if the property was found in the object | |
| 141 | + */ | |
| 142 | + public synchronized boolean has(String name, Scriptable start) { | |
| 143 | + if (isEmpty(name)) { | |
| 144 | + return indexedProps.containsKey(name); | |
| 145 | + } else { | |
| 146 | + synchronized (context) { | |
| 147 | + return context.getAttributesScope(name) != -1; | |
| 148 | + } | |
| 149 | + } | |
| 150 | + } | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * Returns true if the property index is defined. | |
| 154 | + * | |
| 155 | + * @param index the numeric index for the property | |
| 156 | + * @param start the object in which the lookup began | |
| 157 | + * @return true if and only if the property was found in the object | |
| 158 | + */ | |
| 159 | + public synchronized boolean has(int index, Scriptable start) { | |
| 160 | + Integer key = new Integer(index); | |
| 161 | + return indexedProps.containsKey(key); | |
| 162 | + } | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * Sets the value of the named property, creating it if need be. | |
| 166 | + * | |
| 167 | + * @param name the name of the property | |
| 168 | + * @param start the object whose property is being set | |
| 169 | + * @param value value to set the property to | |
| 170 | + */ | |
| 171 | + public void put(String name, Scriptable start, Object value) { | |
| 172 | + if (start == this) { | |
| 173 | + synchronized (this) { | |
| 174 | + if (isEmpty(name)) { | |
| 175 | + indexedProps.put(name, value); | |
| 176 | + } else { | |
| 177 | + synchronized (context) { | |
| 178 | + int scope = context.getAttributesScope(name); | |
| 179 | + if (scope == -1) { | |
| 180 | + scope = ScriptContext.ENGINE_SCOPE; | |
| 181 | + } | |
| 182 | + context.setAttribute(name, jsToJava(value), scope); | |
| 183 | + } | |
| 184 | + } | |
| 185 | + } | |
| 186 | + } else { | |
| 187 | + start.put(name, start, value); | |
| 188 | + } | |
| 189 | + } | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * Sets the value of the indexed property, creating it if need be. | |
| 193 | + * | |
| 194 | + * @param index the numeric index for the property | |
| 195 | + * @param start the object whose property is being set | |
| 196 | + * @param value value to set the property to | |
| 197 | + */ | |
| 198 | + public void put(int index, Scriptable start, Object value) { | |
| 199 | + if (start == this) { | |
| 200 | + synchronized (this) { | |
| 201 | + indexedProps.put(new Integer(index), value); | |
| 202 | + } | |
| 203 | + } else { | |
| 204 | + start.put(index, start, value); | |
| 205 | + } | |
| 206 | + } | |
| 207 | + | |
| 208 | + /** | |
| 209 | + * Removes a named property from the object. | |
| 210 | + * | |
| 211 | + * If the property is not found, no action is taken. | |
| 212 | + * | |
| 213 | + * @param name the name of the property | |
| 214 | + */ | |
| 215 | + public synchronized void delete(String name) { | |
| 216 | + if (isEmpty(name)) { | |
| 217 | + indexedProps.remove(name); | |
| 218 | + } else { | |
| 219 | + synchronized (context) { | |
| 220 | + int scope = context.getAttributesScope(name); | |
| 221 | + if (scope != -1) { | |
| 222 | + context.removeAttribute(name, scope); | |
| 223 | + } | |
| 224 | + } | |
| 225 | + } | |
| 226 | + } | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * Removes the indexed property from the object. | |
| 230 | + * | |
| 231 | + * If the property is not found, no action is taken. | |
| 232 | + * | |
| 233 | + * @param index the numeric index for the property | |
| 234 | + */ | |
| 235 | + public void delete(int index) { | |
| 236 | + indexedProps.remove(new Integer(index)); | |
| 237 | + } | |
| 238 | + | |
| 239 | + /** | |
| 240 | + * Get the prototype of the object. | |
| 241 | + * @return the prototype | |
| 242 | + */ | |
| 243 | + public Scriptable getPrototype() { | |
| 244 | + return prototype; | |
| 245 | + } | |
| 246 | + | |
| 247 | + /** | |
| 248 | + * Set the prototype of the object. | |
| 249 | + * @param prototype the prototype to set | |
| 250 | + */ | |
| 251 | + public void setPrototype(Scriptable prototype) { | |
| 252 | + this.prototype = prototype; | |
| 253 | + } | |
| 254 | + | |
| 255 | + /** | |
| 256 | + * Get the parent scope of the object. | |
| 257 | + * @return the parent scope | |
| 258 | + */ | |
| 259 | + public Scriptable getParentScope() { | |
| 260 | + return parent; | |
| 261 | + } | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * Set the parent scope of the object. | |
| 265 | + * @param parent the parent scope to set | |
| 266 | + */ | |
| 267 | + public void setParentScope(Scriptable parent) { | |
| 268 | + this.parent = parent; | |
| 269 | + } | |
| 270 | + | |
| 271 | + /** | |
| 272 | + * Get an array of property ids. | |
| 273 | + * | |
| 274 | + * Not all property ids need be returned. Those properties | |
| 275 | + * whose ids are not returned are considered non-enumerable. | |
| 276 | + * | |
| 277 | + * @return an array of Objects. Each entry in the array is either | |
| 278 | + * a java.lang.String or a java.lang.Number | |
| 279 | + */ | |
| 280 | + public synchronized Object[] getIds() { | |
| 281 | + String[] keys = getAllKeys(); | |
| 282 | + int size = keys.length + indexedProps.size(); | |
| 283 | + Object[] res = new Object[size]; | |
| 284 | + System.arraycopy(keys, 0, res, 0, keys.length); | |
| 285 | + int i = keys.length; | |
| 286 | + // now add all indexed properties | |
| 287 | + for (Object index : indexedProps.keySet()) { | |
| 288 | + res[i++] = index; | |
| 289 | + } | |
| 290 | + return res; | |
| 291 | + } | |
| 292 | + | |
| 293 | + /** | |
| 294 | + * Get the default value of the object with a given hint. | |
| 295 | + * The hints are String.class for type String, Number.class for type | |
| 296 | + * Number, Scriptable.class for type Object, and Boolean.class for | |
| 297 | + * type Boolean. <p> | |
| 298 | + * | |
| 299 | + * A <code>hint</code> of null means "no hint". | |
| 300 | + * | |
| 301 | + * See ECMA 8.6.2.6. | |
| 302 | + * | |
| 303 | + * @param hint the type hint | |
| 304 | + * @return the default value | |
| 305 | + */ | |
| 306 | + public Object getDefaultValue(Class typeHint) { | |
| 307 | + for (int i=0; i < 2; i++) { | |
| 308 | + boolean tryToString; | |
| 309 | + if (typeHint == ScriptRuntime.StringClass) { | |
| 310 | + tryToString = (i == 0); | |
| 311 | + } else { | |
| 312 | + tryToString = (i == 1); | |
| 313 | + } | |
| 314 | + | |
| 315 | + String methodName; | |
| 316 | + Object[] args; | |
| 317 | + if (tryToString) { | |
| 318 | + methodName = "toString"; | |
| 319 | + args = ScriptRuntime.emptyArgs; | |
| 320 | + } else { | |
| 321 | + methodName = "valueOf"; | |
| 322 | + args = new Object[1]; | |
| 323 | + String hint; | |
| 324 | + if (typeHint == null) { | |
| 325 | + hint = "undefined"; | |
| 326 | + } else if (typeHint == ScriptRuntime.StringClass) { | |
| 327 | + hint = "string"; | |
| 328 | + } else if (typeHint == ScriptRuntime.ScriptableClass) { | |
| 329 | + hint = "object"; | |
| 330 | + } else if (typeHint == ScriptRuntime.FunctionClass) { | |
| 331 | + hint = "function"; | |
| 332 | + } else if (typeHint == ScriptRuntime.BooleanClass | |
| 333 | + || typeHint == Boolean.TYPE) | |
| 334 | + { | |
| 335 | + hint = "boolean"; | |
| 336 | + } else if (typeHint == ScriptRuntime.NumberClass || | |
| 337 | + typeHint == ScriptRuntime.ByteClass || | |
| 338 | + typeHint == Byte.TYPE || | |
| 339 | + typeHint == ScriptRuntime.ShortClass || | |
| 340 | + typeHint == Short.TYPE || | |
| 341 | + typeHint == ScriptRuntime.IntegerClass || | |
| 342 | + typeHint == Integer.TYPE || | |
| 343 | + typeHint == ScriptRuntime.FloatClass || | |
| 344 | + typeHint == Float.TYPE || | |
| 345 | + typeHint == ScriptRuntime.DoubleClass || | |
| 346 | + typeHint == Double.TYPE) | |
| 347 | + { | |
| 348 | + hint = "number"; | |
| 349 | + } else { | |
| 350 | + throw Context.reportRuntimeError( | |
| 351 | + "Invalid JavaScript value of type " + | |
| 352 | + typeHint.toString()); | |
| 353 | + } | |
| 354 | + args[0] = hint; | |
| 355 | + } | |
| 356 | + Object v = ScriptableObject.getProperty(this, methodName); | |
| 357 | + if (!(v instanceof Function)) | |
| 358 | + continue; | |
| 359 | + Function fun = (Function) v; | |
| 360 | + Context cx = RhinoScriptEngine.enterContext(); | |
| 361 | + try { | |
| 362 | + v = fun.call(cx, fun.getParentScope(), this, args); | |
| 363 | + } finally { | |
| 364 | + cx.exit(); | |
| 365 | + } | |
| 366 | + if (v != null) { | |
| 367 | + if (!(v instanceof Scriptable)) { | |
| 368 | + return v; | |
| 369 | + } | |
| 370 | + if (typeHint == ScriptRuntime.ScriptableClass | |
| 371 | + || typeHint == ScriptRuntime.FunctionClass) | |
| 372 | + { | |
| 373 | + return v; | |
| 374 | + } | |
| 375 | + if (tryToString && v instanceof Wrapper) { | |
| 376 | + // Let a wrapped java.lang.String pass for a primitive | |
| 377 | + // string. | |
| 378 | + Object u = ((Wrapper)v).unwrap(); | |
| 379 | + if (u instanceof String) | |
| 380 | + return u; | |
| 381 | + } | |
| 382 | + } | |
| 383 | + } | |
| 384 | + // fall through to error | |
| 385 | + String arg = (typeHint == null) ? "undefined" : typeHint.getName(); | |
| 386 | + throw Context.reportRuntimeError( | |
| 387 | + "Cannot find default value for object " + arg); | |
| 388 | + } | |
| 389 | + | |
| 390 | + /** | |
| 391 | + * Implements the instanceof operator. | |
| 392 | + * | |
| 393 | + * @param instance The value that appeared on the LHS of the instanceof | |
| 394 | + * operator | |
| 395 | + * @return true if "this" appears in value's prototype chain | |
| 396 | + * | |
| 397 | + */ | |
| 398 | + public boolean hasInstance(Scriptable instance) { | |
| 399 | + // Default for JS objects (other than Function) is to do prototype | |
| 400 | + // chasing. | |
| 401 | + Scriptable proto = instance.getPrototype(); | |
| 402 | + while (proto != null) { | |
| 403 | + if (proto.equals(this)) return true; | |
| 404 | + proto = proto.getPrototype(); | |
| 405 | + } | |
| 406 | + return false; | |
| 407 | + } | |
| 408 | + | |
| 409 | + private String[] getAllKeys() { | |
| 410 | + ArrayList<String> list = new ArrayList<String>(); | |
| 411 | + synchronized (context) { | |
| 412 | + for (int scope : context.getScopes()) { | |
| 413 | + Bindings bindings = context.getBindings(scope); | |
| 414 | + if (bindings != null) { | |
| 415 | + list.ensureCapacity(bindings.size()); | |
| 416 | + for (String key : bindings.keySet()) { | |
| 417 | + list.add(key); | |
| 418 | + } | |
| 419 | + } | |
| 420 | + } | |
| 421 | + } | |
| 422 | + String[] res = new String[list.size()]; | |
| 423 | + list.toArray(res); | |
| 424 | + return res; | |
| 425 | + } | |
| 426 | + | |
| 427 | + /** | |
| 428 | + * We convert script values to the nearest Java value. | |
| 429 | + * We unwrap wrapped Java objects so that access from | |
| 430 | + * Bindings.get() would return "workable" value for Java. | |
| 431 | + * But, at the same time, we need to make few special cases | |
| 432 | + * and hence the following function is used. | |
| 433 | + */ | |
| 434 | + private Object jsToJava(Object jsObj) { | |
| 435 | + if (jsObj instanceof Wrapper) { | |
| 436 | + Wrapper njb = (Wrapper) jsObj; | |
| 437 | + /* importClass feature of ImporterTopLevel puts | |
| 438 | + * NativeJavaClass in global scope. If we unwrap | |
| 439 | + * it, importClass won't work. | |
| 440 | + */ | |
| 441 | + if (njb instanceof NativeJavaClass) { | |
| 442 | + return njb; | |
| 443 | + } | |
| 444 | + | |
| 445 | + /* script may use Java primitive wrapper type objects | |
| 446 | + * (such as java.lang.Integer, java.lang.Boolean etc) | |
| 447 | + * explicitly. If we unwrap, then these script objects | |
| 448 | + * will become script primitive types. For example, | |
| 449 | + * | |
| 450 | + * var x = new java.lang.Double(3.0); print(typeof x); | |
| 451 | + * | |
| 452 | + * will print 'number'. We don't want that to happen. | |
| 453 | + */ | |
| 454 | + Object obj = njb.unwrap(); | |
| 455 | + if (obj instanceof Number || obj instanceof String || | |
| 456 | + obj instanceof Boolean || obj instanceof Character) { | |
| 457 | + // special type wrapped -- we just leave it as is. | |
| 458 | + return njb; | |
| 459 | + } else { | |
| 460 | + // return unwrapped object for any other object. | |
| 461 | + return obj; | |
| 462 | + } | |
| 463 | + } else { // not-a-Java-wrapper | |
| 464 | + return jsObj; | |
| 465 | + } | |
| 466 | + } | |
| 467 | +} | |
| @@ -0,0 +1,338 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package com.sun.script.javascript; | |
| 27 | + | |
| 28 | +import sun.org.mozilla.javascript.internal.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * JSAdapter is java.lang.reflect.Proxy equivalent for JavaScript. JSAdapter | |
| 33 | + * calls specially named JavaScript methods on an adaptee object when property | |
| 34 | + * access is attempted on it. | |
| 35 | + * | |
| 36 | + * Example: | |
| 37 | + * | |
| 38 | + * var y = { | |
| 39 | + * __get__ : function (name) { ... } | |
| 40 | + * __has__ : function (name) { ... } | |
| 41 | + * __put__ : function (name, value) {...} | |
| 42 | + * __delete__ : function (name) { ... } | |
| 43 | + * __getIds__ : function () { ... } | |
| 44 | + * }; | |
| 45 | + * | |
| 46 | + * var x = new JSAdapter(y); | |
| 47 | + * | |
| 48 | + * x.i; // calls y.__get__ | |
| 49 | + * i in x; // calls y.__has__ | |
| 50 | + * x.p = 10; // calls y.__put__ | |
| 51 | + * delete x.p; // calls y.__delete__ | |
| 52 | + * for (i in x) { print(i); } // calls y.__getIds__ | |
| 53 | + * | |
| 54 | + * If a special JavaScript method is not found in the adaptee, then JSAdapter | |
| 55 | + * forwards the property access to the adaptee itself. | |
| 56 | + * | |
| 57 | + * JavaScript caller of adapter object is isolated from the fact that | |
| 58 | + * the property access/mutation/deletion are really calls to | |
| 59 | + * JavaScript methods on adaptee. Use cases include 'smart' | |
| 60 | + * properties, property access tracing/debugging, encaptulation with | |
| 61 | + * easy client access - in short JavaScript becomes more "Self" like. | |
| 62 | + * | |
| 63 | + * Note that Rhino already supports special properties like __proto__ | |
| 64 | + * (to set, get prototype), __parent__ (to set, get parent scope). We | |
| 65 | + * follow the same double underscore nameing convention here. Similarly | |
| 66 | + * the name JSAdapter is derived from JavaAdapter -- which is a facility | |
| 67 | + * to extend, implement Java classes/interfaces by JavaScript. | |
| 68 | + * | |
| 69 | + * @author A. Sundararajan | |
| 70 | + * @since 1.6 | |
| 71 | + */ | |
| 72 | +public final class JSAdapter implements Scriptable, Function { | |
| 73 | + private JSAdapter(Scriptable obj) { | |
| 74 | + setAdaptee(obj); | |
| 75 | + } | |
| 76 | + | |
| 77 | + // initializer to setup JSAdapter prototype in the given scope | |
| 78 | + public static void init(Context cx, Scriptable scope, boolean sealed) | |
| 79 | + throws RhinoException { | |
| 80 | + JSAdapter obj = new JSAdapter(cx.newObject(scope)); | |
| 81 | + obj.setParentScope(scope); | |
| 82 | + obj.setPrototype(getFunctionPrototype(scope)); | |
| 83 | + obj.isPrototype = true; | |
| 84 | + ScriptableObject.defineProperty(scope, "JSAdapter", obj, | |
| 85 | + ScriptableObject.DONTENUM); | |
| 86 | + } | |
| 87 | + | |
| 88 | + public String getClassName() { | |
| 89 | + return "JSAdapter"; | |
| 90 | + } | |
| 91 | + | |
| 92 | + public Object get(String name, Scriptable start) { | |
| 93 | + Function func = getAdapteeFunction(GET_PROP); | |
| 94 | + if (func != null) { | |
| 95 | + return call(func, new Object[] { name }); | |
| 96 | + } else { | |
| 97 | + start = getAdaptee(); | |
| 98 | + return start.get(name, start); | |
| 99 | + } | |
| 100 | + } | |
| 101 | + | |
| 102 | + public Object get(int index, Scriptable start) { | |
| 103 | + Function func = getAdapteeFunction(GET_PROP); | |
| 104 | + if (func != null) { | |
| 105 | + return call(func, new Object[] { new Integer(index) }); | |
| 106 | + } else { | |
| 107 | + start = getAdaptee(); | |
| 108 | + return start.get(index, start); | |
| 109 | + } | |
| 110 | + } | |
| 111 | + | |
| 112 | + public boolean has(String name, Scriptable start) { | |
| 113 | + Function func = getAdapteeFunction(HAS_PROP); | |
| 114 | + if (func != null) { | |
| 115 | + Object res = call(func, new Object[] { name }); | |
| 116 | + return Context.toBoolean(res); | |
| 117 | + } else { | |
| 118 | + start = getAdaptee(); | |
| 119 | + return start.has(name, start); | |
| 120 | + } | |
| 121 | + } | |
| 122 | + | |
| 123 | + public boolean has(int index, Scriptable start) { | |
| 124 | + Function func = getAdapteeFunction(HAS_PROP); | |
| 125 | + if (func != null) { | |
| 126 | + Object res = call(func, new Object[] { new Integer(index) }); | |
| 127 | + return Context.toBoolean(res); | |
| 128 | + } else { | |
| 129 | + start = getAdaptee(); | |
| 130 | + return start.has(index, start); | |
| 131 | + } | |
| 132 | + } | |
| 133 | + | |
| 134 | + public void put(String name, Scriptable start, Object value) { | |
| 135 | + if (start == this) { | |
| 136 | + Function func = getAdapteeFunction(PUT_PROP); | |
| 137 | + if (func != null) { | |
| 138 | + call(func, new Object[] { name, value }); | |
| 139 | + } else { | |
| 140 | + start = getAdaptee(); | |
| 141 | + start.put(name, start, value); | |
| 142 | + } | |
| 143 | + } else { | |
| 144 | + start.put(name, start, value); | |
| 145 | + } | |
| 146 | + } | |
| 147 | + | |
| 148 | + public void put(int index, Scriptable start, Object value) { | |
| 149 | + if (start == this) { | |
| 150 | + Function func = getAdapteeFunction(PUT_PROP); | |
| 151 | + if( func != null) { | |
| 152 | + call(func, new Object[] { new Integer(index), value }); | |
| 153 | + } else { | |
| 154 | + start = getAdaptee(); | |
| 155 | + start.put(index, start, value); | |
| 156 | + } | |
| 157 | + } else { | |
| 158 | + start.put(index, start, value); | |
| 159 | + } | |
| 160 | + } | |
| 161 | + | |
| 162 | + public void delete(String name) { | |
| 163 | + Function func = getAdapteeFunction(DEL_PROP); | |
| 164 | + if (func != null) { | |
| 165 | + call(func, new Object[] { name }); | |
| 166 | + } else { | |
| 167 | + getAdaptee().delete(name); | |
| 168 | + } | |
| 169 | + } | |
| 170 | + | |
| 171 | + public void delete(int index) { | |
| 172 | + Function func = getAdapteeFunction(DEL_PROP); | |
| 173 | + if (func != null) { | |
| 174 | + call(func, new Object[] { new Integer(index) }); | |
| 175 | + } else { | |
| 176 | + getAdaptee().delete(index); | |
| 177 | + } | |
| 178 | + } | |
| 179 | + | |
| 180 | + public Scriptable getPrototype() { | |
| 181 | + return prototype; | |
| 182 | + } | |
| 183 | + | |
| 184 | + public void setPrototype(Scriptable prototype) { | |
| 185 | + this.prototype = prototype; | |
| 186 | + } | |
| 187 | + | |
| 188 | + public Scriptable getParentScope() { | |
| 189 | + return parent; | |
| 190 | + } | |
| 191 | + | |
| 192 | + public void setParentScope(Scriptable parent) { | |
| 193 | + this.parent = parent; | |
| 194 | + } | |
| 195 | + | |
| 196 | + public Object[] getIds() { | |
| 197 | + Function func = getAdapteeFunction(GET_PROPIDS); | |
| 198 | + if (func != null) { | |
| 199 | + Object val = call(func, new Object[0]); | |
| 200 | + // in most cases, adaptee would return native JS array | |
| 201 | + if (val instanceof NativeArray) { | |
| 202 | + NativeArray array = (NativeArray) val; | |
| 203 | + Object[] res = new Object[(int)array.getLength()]; | |
| 204 | + for (int index = 0; index < res.length; index++) { | |
| 205 | + res[index] = mapToId(array.get(index, array)); | |
| 206 | + } | |
| 207 | + return res; | |
| 208 | + } else if (val instanceof NativeJavaArray) { | |
| 209 | + // may be attempt wrapped Java array | |
| 210 | + Object tmp = ((NativeJavaArray)val).unwrap(); | |
| 211 | + Object[] res; | |
| 212 | + if (tmp.getClass() == Object[].class) { | |
| 213 | + Object[] array = (Object[]) tmp; | |
| 214 | + res = new Object[array.length]; | |
| 215 | + for (int index = 0; index < array.length; index++) { | |
| 216 | + res[index] = mapToId(array[index]); | |
| 217 | + } | |
| 218 | + } else { | |
| 219 | + // just return an empty array | |
| 220 | + res = Context.emptyArgs; | |
| 221 | + } | |
| 222 | + return res; | |
| 223 | + } else { | |
| 224 | + // some other return type, just return empty array | |
| 225 | + return Context.emptyArgs; | |
| 226 | + } | |
| 227 | + } else { | |
| 228 | + return getAdaptee().getIds(); | |
| 229 | + } | |
| 230 | + } | |
| 231 | + | |
| 232 | + public boolean hasInstance(Scriptable scriptable) { | |
| 233 | + if (scriptable instanceof JSAdapter) { | |
| 234 | + return true; | |
| 235 | + } else { | |
| 236 | + Scriptable proto = scriptable.getPrototype(); | |
| 237 | + while (proto != null) { | |
| 238 | + if (proto.equals(this)) return true; | |
| 239 | + proto = proto.getPrototype(); | |
| 240 | + } | |
| 241 | + return false; | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 245 | + public Object getDefaultValue(Class hint) { | |
| 246 | + return getAdaptee().getDefaultValue(hint); | |
| 247 | + } | |
| 248 | + | |
| 249 | + public Object call(Context cx, Scriptable scope, Scriptable thisObj, | |
| 250 | + Object[] args) | |
| 251 | + throws RhinoException { | |
| 252 | + if (isPrototype) { | |
| 253 | + return construct(cx, scope, args); | |
| 254 | + } else { | |
| 255 | + Scriptable tmp = getAdaptee(); | |
| 256 | + if (tmp instanceof Function) { | |
| 257 | + return ((Function)tmp).call(cx, scope, tmp, args); | |
| 258 | + } else { | |
| 259 | + throw Context.reportRuntimeError("TypeError: not a function"); | |
| 260 | + } | |
| 261 | + } | |
| 262 | + } | |
| 263 | + | |
| 264 | + public Scriptable construct(Context cx, Scriptable scope, Object[] args) | |
| 265 | + throws RhinoException { | |
| 266 | + if (isPrototype) { | |
| 267 | + Scriptable topLevel = ScriptableObject.getTopLevelScope(scope); | |
| 268 | + JSAdapter newObj; | |
| 269 | + if (args.length > 0) { | |
| 270 | + newObj = new JSAdapter(Context.toObject(args[0], topLevel)); | |
| 271 | + } else { | |
| 272 | + throw Context.reportRuntimeError("JSAdapter requires adaptee"); | |
| 273 | + } | |
| 274 | + return newObj; | |
| 275 | + } else { | |
| 276 | + Scriptable tmp = getAdaptee(); | |
| 277 | + if (tmp instanceof Function) { | |
| 278 | + return ((Function)tmp).construct(cx, scope, args); | |
| 279 | + } else { | |
| 280 | + throw Context.reportRuntimeError("TypeError: not a constructor"); | |
| 281 | + } | |
| 282 | + } | |
| 283 | + } | |
| 284 | + | |
| 285 | + public Scriptable getAdaptee() { | |
| 286 | + return adaptee; | |
| 287 | + } | |
| 288 | + | |
| 289 | + public void setAdaptee(Scriptable adaptee) { | |
| 290 | + if (adaptee == null) { | |
| 291 | + throw new NullPointerException("adaptee can not be null"); | |
| 292 | + } | |
| 293 | + this.adaptee = adaptee; | |
| 294 | + } | |
| 295 | + | |
| 296 | + //-- internals only below this point | |
| 297 | + | |
| 298 | + // map a property id. Property id can only be an Integer or String | |
| 299 | + private Object mapToId(Object tmp) { | |
| 300 | + if (tmp instanceof Double) { | |
| 301 | + return new Integer(((Double)tmp).intValue()); | |
| 302 | + } else { | |
| 303 | + return Context.toString(tmp); | |
| 304 | + } | |
| 305 | + } | |
| 306 | + | |
| 307 | + private static Scriptable getFunctionPrototype(Scriptable scope) { | |
| 308 | + return ScriptableObject.getFunctionPrototype(scope); | |
| 309 | + } | |
| 310 | + | |
| 311 | + private Function getAdapteeFunction(String name) { | |
| 312 | + Object o = ScriptableObject.getProperty(getAdaptee(), name); | |
| 313 | + return (o instanceof Function)? (Function)o : null; | |
| 314 | + } | |
| 315 | + | |
| 316 | + private Object call(Function func, Object[] args) { | |
| 317 | + Context cx = Context.getCurrentContext(); | |
| 318 | + Scriptable thisObj = getAdaptee(); | |
| 319 | + Scriptable scope = func.getParentScope(); | |
| 320 | + try { | |
| 321 | + return func.call(cx, scope, thisObj, args); | |
| 322 | + } catch (RhinoException re) { | |
| 323 | + throw Context.reportRuntimeError(re.getMessage()); | |
| 324 | + } | |
| 325 | + } | |
| 326 | + | |
| 327 | + private Scriptable prototype; | |
| 328 | + private Scriptable parent; | |
| 329 | + private Scriptable adaptee; | |
| 330 | + private boolean isPrototype; | |
| 331 | + | |
| 332 | + // names of adaptee JavaScript functions | |
| 333 | + private static final String GET_PROP = "__get__"; | |
| 334 | + private static final String HAS_PROP = "__has__"; | |
| 335 | + private static final String PUT_PROP = "__put__"; | |
| 336 | + private static final String DEL_PROP = "__delete__"; | |
| 337 | + private static final String GET_PROPIDS = "__getIds__"; | |
| 338 | +} | |
| @@ -0,0 +1,106 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package com.sun.script.javascript; | |
| 27 | + | |
| 28 | +import javax.script.Invocable; | |
| 29 | +import sun.org.mozilla.javascript.internal.*; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * This class implements Rhino-like JavaAdapter to help implement a Java | |
| 33 | + * interface in JavaScript. We support this using Invocable.getInterface. | |
| 34 | + * Using this JavaAdapter, script author could write: | |
| 35 | + * | |
| 36 | + * var r = new java.lang.Runnable() { | |
| 37 | + * run: function() { script... } | |
| 38 | + * }; | |
| 39 | + * | |
| 40 | + * r.run(); | |
| 41 | + * new java.lang.Thread(r).start(); | |
| 42 | + * | |
| 43 | + * Note that Rhino's JavaAdapter support allows extending a Java class and/or | |
| 44 | + * implementing one or more interfaces. This JavaAdapter implementation does | |
| 45 | + * not support these. | |
| 46 | + * | |
| 47 | + * @author A. Sundararajan | |
| 48 | + * @since 1.6 | |
| 49 | + */ | |
| 50 | +final class JavaAdapter extends ScriptableObject implements Function { | |
| 51 | + private JavaAdapter(Invocable engine) { | |
| 52 | + this.engine = engine; | |
| 53 | + } | |
| 54 | + | |
| 55 | + static void init(Context cx, Scriptable scope, boolean sealed) | |
| 56 | + throws RhinoException { | |
| 57 | + RhinoTopLevel topLevel = (RhinoTopLevel) scope; | |
| 58 | + Invocable engine = topLevel.getScriptEngine(); | |
| 59 | + JavaAdapter obj = new JavaAdapter(engine); | |
| 60 | + obj.setParentScope(scope); | |
| 61 | + obj.setPrototype(getFunctionPrototype(scope)); | |
| 62 | + /* | |
| 63 | + * Note that we can't use defineProperty. A property of this | |
| 64 | + * name is already defined in Context.initStandardObjects. We | |
| 65 | + * simply overwrite the property value! | |
| 66 | + */ | |
| 67 | + ScriptableObject.putProperty(topLevel, "JavaAdapter", obj); | |
| 68 | + } | |
| 69 | + | |
| 70 | + public String getClassName() { | |
| 71 | + return "JavaAdapter"; | |
| 72 | + } | |
| 73 | + | |
| 74 | + public Object call(Context cx, Scriptable scope, Scriptable thisObj, | |
| 75 | + Object[] args) throws RhinoException { | |
| 76 | + return construct(cx, scope, args); | |
| 77 | + } | |
| 78 | + | |
| 79 | + public Scriptable construct(Context cx, Scriptable scope, Object[] args) | |
| 80 | + throws RhinoException { | |
| 81 | + if (args.length == 2) { | |
| 82 | + Class<?> clazz = null; | |
| 83 | + Object obj1 = args[0]; | |
| 84 | + if (obj1 instanceof Wrapper) { | |
| 85 | + Object o = ((Wrapper)obj1).unwrap(); | |
| 86 | + if (o instanceof Class && ((Class)o).isInterface()) { | |
| 87 | + clazz = (Class) o; | |
| 88 | + } | |
| 89 | + } else if (obj1 instanceof Class) { | |
| 90 | + if (((Class)obj1).isInterface()) { | |
| 91 | + clazz = (Class) obj1; | |
| 92 | + } | |
| 93 | + } | |
| 94 | + if (clazz == null) { | |
| 95 | + throw Context.reportRuntimeError("JavaAdapter: first arg should be interface Class"); | |
| 96 | + } | |
| 97 | + | |
| 98 | + Scriptable topLevel = ScriptableObject.getTopLevelScope(scope); | |
| 99 | + return cx.toObject(engine.getInterface(args[1], clazz), topLevel); | |
| 100 | + } else { | |
| 101 | + throw Context.reportRuntimeError("JavaAdapter requires two arguments"); | |
| 102 | + } | |
| 103 | + } | |
| 104 | + | |
| 105 | + private Invocable engine; | |
| 106 | +} | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +<../../../../../../../mkconfig | |
| 2 | + | |
| 3 | +DIRS=\ | |
| 4 | + services\ | |
| 5 | + | |
| 6 | +<$ROOT/mkfiles/mksubdirs | |
| @@ -0,0 +1,5 @@ | ||
| 1 | + | |
| 2 | +#script engines supported | |
| 3 | + | |
| 4 | +com.sun.script.javascript.RhinoScriptEngineFactory #javascript | |
| 5 | + | |
| @@ -0,0 +1,2 @@ | ||
| 1 | +<../../../../../../../../mkconfig | |
| 2 | + | |
| @@ -0,0 +1,75 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package com.sun.script.javascript; | |
| 27 | + | |
| 28 | +import java.util.*; | |
| 29 | +import sun.org.mozilla.javascript.internal.*; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * This class prevents script access to certain sensitive classes. | |
| 33 | + * Note that this class checks over and above SecurityManager. i.e., although | |
| 34 | + * a SecurityManager would pass, class shutter may still prevent access. | |
| 35 | + * | |
| 36 | + * @author A. Sundararajan | |
| 37 | + * @since 1.6 | |
| 38 | + */ | |
| 39 | +final class RhinoClassShutter implements ClassShutter { | |
| 40 | + private static Map<String, Boolean> protectedClasses; | |
| 41 | + private static RhinoClassShutter theInstance; | |
| 42 | + | |
| 43 | + private RhinoClassShutter() { | |
| 44 | + } | |
| 45 | + | |
| 46 | + static synchronized ClassShutter getInstance() { | |
| 47 | + if (theInstance == null) { | |
| 48 | + theInstance = new RhinoClassShutter(); | |
| 49 | + protectedClasses = new HashMap<String, Boolean>(); | |
| 50 | + | |
| 51 | + // For now, we just have AccessController. Allowing scripts | |
| 52 | + // to this class will allow it to execute doPrivileged in | |
| 53 | + // bootstrap context. We can add more classes for other reasons. | |
| 54 | + protectedClasses.put("java.security.AccessController", Boolean.TRUE); | |
| 55 | + } | |
| 56 | + return theInstance; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public boolean visibleToScripts(String fullClassName) { | |
| 60 | + // first do the security check. | |
| 61 | + SecurityManager sm = System.getSecurityManager(); | |
| 62 | + if (sm != null) { | |
| 63 | + int i = fullClassName.lastIndexOf("."); | |
| 64 | + if (i != -1) { | |
| 65 | + try { | |
| 66 | + sm.checkPackageAccess(fullClassName.substring(0, i)); | |
| 67 | + } catch (SecurityException se) { | |
| 68 | + return false; | |
| 69 | + } | |
| 70 | + } | |
| 71 | + } | |
| 72 | + // now, check is it a protected class. | |
| 73 | + return protectedClasses.get(fullClassName) == null; | |
| 74 | + } | |
| 75 | +} | |
| @@ -0,0 +1,78 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package com.sun.script.javascript; | |
| 27 | +import javax.script.*; | |
| 28 | +import sun.org.mozilla.javascript.internal.*; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Represents compiled JavaScript code. | |
| 32 | + * | |
| 33 | + * @author Mike Grogan | |
| 34 | + * @since 1.6 | |
| 35 | + */ | |
| 36 | +final class RhinoCompiledScript extends CompiledScript { | |
| 37 | + | |
| 38 | + private RhinoScriptEngine engine; | |
| 39 | + private Script script; | |
| 40 | + | |
| 41 | + | |
| 42 | + RhinoCompiledScript(RhinoScriptEngine engine, Script script) { | |
| 43 | + this.engine = engine; | |
| 44 | + this.script = script; | |
| 45 | + } | |
| 46 | + | |
| 47 | + public Object eval(ScriptContext context) throws ScriptException { | |
| 48 | + | |
| 49 | + Object result = null; | |
| 50 | + Context cx = RhinoScriptEngine.enterContext(); | |
| 51 | + try { | |
| 52 | + | |
| 53 | + Scriptable scope = engine.getRuntimeScope(context); | |
| 54 | + Object ret = script.exec(cx, scope); | |
| 55 | + result = engine.unwrapReturnValue(ret); | |
| 56 | + } catch (RhinoException re) { | |
| 57 | + int line = (line = re.lineNumber()) == 0 ? -1 : line; | |
| 58 | + String msg; | |
| 59 | + if (re instanceof JavaScriptException) { | |
| 60 | + msg = String.valueOf(((JavaScriptException)re).getValue()); | |
| 61 | + } else { | |
| 62 | + msg = re.toString(); | |
| 63 | + } | |
| 64 | + ScriptException se = new ScriptException(msg, re.sourceName(), line); | |
| 65 | + se.initCause(re); | |
| 66 | + throw se; | |
| 67 | + } finally { | |
| 68 | + Context.exit(); | |
| 69 | + } | |
| 70 | + | |
| 71 | + return result; | |
| 72 | + } | |
| 73 | + | |
| 74 | + public ScriptEngine getEngine() { | |
| 75 | + return engine; | |
| 76 | + } | |
| 77 | + | |
| 78 | +} | |
| @@ -0,0 +1,398 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package com.sun.script.javascript; | |
| 27 | +import com.sun.script.util.*; | |
| 28 | +import javax.script.*; | |
| 29 | +import sun.org.mozilla.javascript.internal.*; | |
| 30 | +import java.lang.reflect.Method; | |
| 31 | +import java.io.*; | |
| 32 | +import java.util.*; | |
| 33 | + | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * Implementation of <code>ScriptEngine</code> using the Mozilla Rhino | |
| 37 | + * interpreter. | |
| 38 | + * | |
| 39 | + * @author Mike Grogan | |
| 40 | + * @author A. Sundararajan | |
| 41 | + * @since 1.6 | |
| 42 | + */ | |
| 43 | +public final class RhinoScriptEngine extends AbstractScriptEngine | |
| 44 | + implements Invocable, Compilable { | |
| 45 | + | |
| 46 | + private static final boolean DEBUG = false; | |
| 47 | + | |
| 48 | + /* Scope where standard JavaScript objects and our | |
| 49 | + * extensions to it are stored. Note that these are not | |
| 50 | + * user defined engine level global variables. These are | |
| 51 | + * variables have to be there on all compliant ECMAScript | |
| 52 | + * scopes. We put these standard objects in this top level. | |
| 53 | + */ | |
| 54 | + private RhinoTopLevel topLevel; | |
| 55 | + | |
| 56 | + /* map used to store indexed properties in engine scope | |
| 57 | + * refer to comment on 'indexedProps' in ExternalScriptable.java. | |
| 58 | + */ | |
| 59 | + private Map<Object, Object> indexedProps; | |
| 60 | + | |
| 61 | + private ScriptEngineFactory factory; | |
| 62 | + private InterfaceImplementor implementor; | |
| 63 | + | |
| 64 | + private static final int languageVersion = getLanguageVersion(); | |
| 65 | + private static final int optimizationLevel = getOptimizationLevel(); | |
| 66 | + static { | |
| 67 | + ContextFactory.initGlobal(new ContextFactory() { | |
| 68 | + protected Context makeContext() { | |
| 69 | + Context cx = super.makeContext(); | |
| 70 | + cx.setLanguageVersion(languageVersion); | |
| 71 | + cx.setOptimizationLevel(optimizationLevel); | |
| 72 | + cx.setClassShutter(RhinoClassShutter.getInstance()); | |
| 73 | + cx.setWrapFactory(RhinoWrapFactory.getInstance()); | |
| 74 | + return cx; | |
| 75 | + } | |
| 76 | + }); | |
| 77 | + } | |
| 78 | + | |
| 79 | + private static final String RHINO_JS_VERSION = "rhino.js.version"; | |
| 80 | + private static int getLanguageVersion() { | |
| 81 | + int version; | |
| 82 | + String tmp = java.security.AccessController.doPrivileged( | |
| 83 | + new sun.security.action.GetPropertyAction(RHINO_JS_VERSION)); | |
| 84 | + if (tmp != null) { | |
| 85 | + version = Integer.parseInt((String)tmp); | |
| 86 | + } else { | |
| 87 | + version = Context.VERSION_1_8; | |
| 88 | + } | |
| 89 | + return version; | |
| 90 | + } | |
| 91 | + | |
| 92 | + private static final String RHINO_OPT_LEVEL = "rhino.opt.level"; | |
| 93 | + private static int getOptimizationLevel() { | |
| 94 | + int optLevel = -1; | |
| 95 | + // disable optimizer under security manager, for now. | |
| 96 | + if (System.getSecurityManager() == null) { | |
| 97 | + optLevel = Integer.getInteger(RHINO_OPT_LEVEL, -1); | |
| 98 | + } | |
| 99 | + return optLevel; | |
| 100 | + } | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * Creates a new instance of RhinoScriptEngine | |
| 104 | + */ | |
| 105 | + public RhinoScriptEngine() { | |
| 106 | + | |
| 107 | + Context cx = enterContext(); | |
| 108 | + try { | |
| 109 | + topLevel = new RhinoTopLevel(cx, this); | |
| 110 | + } finally { | |
| 111 | + cx.exit(); | |
| 112 | + } | |
| 113 | + | |
| 114 | + indexedProps = new HashMap<Object, Object>(); | |
| 115 | + | |
| 116 | + //construct object used to implement getInterface | |
| 117 | + implementor = new InterfaceImplementor(this) { | |
| 118 | + protected boolean isImplemented(Object thiz, Class<?> iface) { | |
| 119 | + Context cx = enterContext(); | |
| 120 | + try { | |
| 121 | + if (thiz != null && !(thiz instanceof Scriptable)) { | |
| 122 | + thiz = cx.toObject(thiz, topLevel); | |
| 123 | + } | |
| 124 | + Scriptable engineScope = getRuntimeScope(context); | |
| 125 | + Scriptable localScope = (thiz != null)? (Scriptable) thiz : | |
| 126 | + engineScope; | |
| 127 | + for (Method method : iface.getMethods()) { | |
| 128 | + // ignore methods of java.lang.Object class | |
| 129 | + if (method.getDeclaringClass() == Object.class) { | |
| 130 | + continue; | |
| 131 | + } | |
| 132 | + Object obj = ScriptableObject.getProperty(localScope, method.getName()); | |
| 133 | + if (! (obj instanceof Function)) { | |
| 134 | + return false; | |
| 135 | + } | |
| 136 | + } | |
| 137 | + return true; | |
| 138 | + } finally { | |
| 139 | + cx.exit(); | |
| 140 | + } | |
| 141 | + } | |
| 142 | + | |
| 143 | + protected Object convertResult(Method method, Object res) | |
| 144 | + throws ScriptException { | |
| 145 | + Class desiredType = method.getReturnType(); | |
| 146 | + if (desiredType == Void.TYPE) { | |
| 147 | + return null; | |
| 148 | + } else { | |
| 149 | + return Context.jsToJava(res, desiredType); | |
| 150 | + } | |
| 151 | + } | |
| 152 | + }; | |
| 153 | + } | |
| 154 | + | |
| 155 | + public Object eval(Reader reader, ScriptContext ctxt) | |
| 156 | + throws ScriptException { | |
| 157 | + Object ret; | |
| 158 | + | |
| 159 | + Context cx = enterContext(); | |
| 160 | + try { | |
| 161 | + Scriptable scope = getRuntimeScope(ctxt); | |
| 162 | + String filename = (String) get(ScriptEngine.FILENAME); | |
| 163 | + filename = filename == null ? "<Unknown source>" : filename; | |
| 164 | + | |
| 165 | + ret = cx.evaluateReader(scope, reader, filename , 1, null); | |
| 166 | + } catch (RhinoException re) { | |
| 167 | + if (DEBUG) re.printStackTrace(); | |
| 168 | + int line = (line = re.lineNumber()) == 0 ? -1 : line; | |
| 169 | + String msg; | |
| 170 | + if (re instanceof JavaScriptException) { | |
| 171 | + msg = String.valueOf(((JavaScriptException)re).getValue()); | |
| 172 | + } else { | |
| 173 | + msg = re.toString(); | |
| 174 | + } | |
| 175 | + ScriptException se = new ScriptException(msg, re.sourceName(), line); | |
| 176 | + se.initCause(re); | |
| 177 | + throw se; | |
| 178 | + } catch (IOException ee) { | |
| 179 | + throw new ScriptException(ee); | |
| 180 | + } finally { | |
| 181 | + cx.exit(); | |
| 182 | + } | |
| 183 | + | |
| 184 | + return unwrapReturnValue(ret); | |
| 185 | + } | |
| 186 | + | |
| 187 | + public Object eval(String script, ScriptContext ctxt) throws ScriptException { | |
| 188 | + if (script == null) { | |
| 189 | + throw new NullPointerException("null script"); | |
| 190 | + } | |
| 191 | + return eval(new StringReader(script) , ctxt); | |
| 192 | + } | |
| 193 | + | |
| 194 | + public ScriptEngineFactory getFactory() { | |
| 195 | + if (factory != null) { | |
| 196 | + return factory; | |
| 197 | + } else { | |
| 198 | + return new RhinoScriptEngineFactory(); | |
| 199 | + } | |
| 200 | + } | |
| 201 | + | |
| 202 | + public Bindings createBindings() { | |
| 203 | + return new SimpleBindings(); | |
| 204 | + } | |
| 205 | + | |
| 206 | + //Invocable methods | |
| 207 | + public Object invokeFunction(String name, Object... args) | |
| 208 | + throws ScriptException, NoSuchMethodException { | |
| 209 | + return invoke(null, name, args); | |
| 210 | + } | |
| 211 | + | |
| 212 | + public Object invokeMethod(Object thiz, String name, Object... args) | |
| 213 | + throws ScriptException, NoSuchMethodException { | |
| 214 | + if (thiz == null) { | |
| 215 | + throw new IllegalArgumentException("script object can not be null"); | |
| 216 | + } | |
| 217 | + return invoke(thiz, name, args); | |
| 218 | + } | |
| 219 | + | |
| 220 | + private Object invoke(Object thiz, String name, Object... args) | |
| 221 | + throws ScriptException, NoSuchMethodException { | |
| 222 | + Context cx = enterContext(); | |
| 223 | + try { | |
| 224 | + if (name == null) { | |
| 225 | + throw new NullPointerException("method name is null"); | |
| 226 | + } | |
| 227 | + | |
| 228 | + if (thiz != null && !(thiz instanceof Scriptable)) { | |
| 229 | + thiz = cx.toObject(thiz, topLevel); | |
| 230 | + } | |
| 231 | + | |
| 232 | + Scriptable engineScope = getRuntimeScope(context); | |
| 233 | + Scriptable localScope = (thiz != null)? (Scriptable) thiz : | |
| 234 | + engineScope; | |
| 235 | + Object obj = ScriptableObject.getProperty(localScope, name); | |
| 236 | + if (! (obj instanceof Function)) { | |
| 237 | + throw new NoSuchMethodException("no such method: " + name); | |
| 238 | + } | |
| 239 | + | |
| 240 | + Function func = (Function) obj; | |
| 241 | + Scriptable scope = func.getParentScope(); | |
| 242 | + if (scope == null) { | |
| 243 | + scope = engineScope; | |
| 244 | + } | |
| 245 | + Object result = func.call(cx, scope, localScope, | |
| 246 | + wrapArguments(args)); | |
| 247 | + return unwrapReturnValue(result); | |
| 248 | + } catch (RhinoException re) { | |
| 249 | + if (DEBUG) re.printStackTrace(); | |
| 250 | + int line = (line = re.lineNumber()) == 0 ? -1 : line; | |
| 251 | + ScriptException se = new ScriptException(re.toString(), re.sourceName(), line); | |
| 252 | + se.initCause(re); | |
| 253 | + throw se; | |
| 254 | + } finally { | |
| 255 | + cx.exit(); | |
| 256 | + } | |
| 257 | + } | |
| 258 | + | |
| 259 | + public <T> T getInterface(Class<T> clasz) { | |
| 260 | + try { | |
| 261 | + return implementor.getInterface(null, clasz); | |
| 262 | + } catch (ScriptException e) { | |
| 263 | + return null; | |
| 264 | + } | |
| 265 | + } | |
| 266 | + | |
| 267 | + public <T> T getInterface(Object thiz, Class<T> clasz) { | |
| 268 | + if (thiz == null) { | |
| 269 | + throw new IllegalArgumentException("script object can not be null"); | |
| 270 | + } | |
| 271 | + | |
| 272 | + try { | |
| 273 | + return implementor.getInterface(thiz, clasz); | |
| 274 | + } catch (ScriptException e) { | |
| 275 | + return null; | |
| 276 | + } | |
| 277 | + } | |
| 278 | + | |
| 279 | + private static final String printSource = | |
| 280 | + "function print(str, newline) { \n" + | |
| 281 | + " if (typeof(str) == 'undefined') { \n" + | |
| 282 | + " str = 'undefined'; \n" + | |
| 283 | + " } else if (str == null) { \n" + | |
| 284 | + " str = 'null'; \n" + | |
| 285 | + " } \n" + | |
| 286 | + " var out = context.getWriter(); \n" + | |
| 287 | + " if (!(out instanceof java.io.PrintWriter))\n" + | |
| 288 | + " out = new java.io.PrintWriter(out); \n" + | |
| 289 | + " out.print(String(str)); \n" + | |
| 290 | + " if (newline) out.print('\\n'); \n" + | |
| 291 | + " out.flush(); \n" + | |
| 292 | + "}\n" + | |
| 293 | + "function println(str) { \n" + | |
| 294 | + " print(str, true); \n" + | |
| 295 | + "}"; | |
| 296 | + | |
| 297 | + Scriptable getRuntimeScope(ScriptContext ctxt) { | |
| 298 | + if (ctxt == null) { | |
| 299 | + throw new NullPointerException("null script context"); | |
| 300 | + } | |
| 301 | + | |
| 302 | + // we create a scope for the given ScriptContext | |
| 303 | + Scriptable newScope = new ExternalScriptable(ctxt, indexedProps); | |
| 304 | + | |
| 305 | + // Set the prototype of newScope to be 'topLevel' so that | |
| 306 | + // JavaScript standard objects are visible from the scope. | |
| 307 | + newScope.setPrototype(topLevel); | |
| 308 | + | |
| 309 | + // define "context" variable in the new scope | |
| 310 | + newScope.put("context", newScope, ctxt); | |
| 311 | + | |
| 312 | + // define "print", "println" functions in the new scope | |
| 313 | + Context cx = enterContext(); | |
| 314 | + try { | |
| 315 | + cx.evaluateString(newScope, printSource, "print", 1, null); | |
| 316 | + } finally { | |
| 317 | + cx.exit(); | |
| 318 | + } | |
| 319 | + return newScope; | |
| 320 | + } | |
| 321 | + | |
| 322 | + | |
| 323 | + //Compilable methods | |
| 324 | + public CompiledScript compile(String script) throws ScriptException { | |
| 325 | + return compile(new StringReader(script)); | |
| 326 | + } | |
| 327 | + | |
| 328 | + public CompiledScript compile(java.io.Reader script) throws ScriptException { | |
| 329 | + CompiledScript ret = null; | |
| 330 | + Context cx = enterContext(); | |
| 331 | + | |
| 332 | + try { | |
| 333 | + String fileName = (String) get(ScriptEngine.FILENAME); | |
| 334 | + if (fileName == null) { | |
| 335 | + fileName = "<Unknown Source>"; | |
| 336 | + } | |
| 337 | + | |
| 338 | + Scriptable scope = getRuntimeScope(context); | |
| 339 | + Script scr = cx.compileReader(scope, script, fileName, 1, null); | |
| 340 | + ret = new RhinoCompiledScript(this, scr); | |
| 341 | + } catch (Exception e) { | |
| 342 | + if (DEBUG) e.printStackTrace(); | |
| 343 | + throw new ScriptException(e); | |
| 344 | + } finally { | |
| 345 | + cx.exit(); | |
| 346 | + } | |
| 347 | + return ret; | |
| 348 | + } | |
| 349 | + | |
| 350 | + | |
| 351 | + //package-private helpers | |
| 352 | + | |
| 353 | + static Context enterContext() { | |
| 354 | + // call this always so that initializer of this class runs | |
| 355 | + // and initializes custom wrap factory and class shutter. | |
| 356 | + return Context.enter(); | |
| 357 | + } | |
| 358 | + | |
| 359 | + void setEngineFactory(ScriptEngineFactory fac) { | |
| 360 | + factory = fac; | |
| 361 | + } | |
| 362 | + | |
| 363 | + Object[] wrapArguments(Object[] args) { | |
| 364 | + if (args == null) { | |
| 365 | + return Context.emptyArgs; | |
| 366 | + } | |
| 367 | + Object[] res = new Object[args.length]; | |
| 368 | + for (int i = 0; i < res.length; i++) { | |
| 369 | + res[i] = Context.javaToJS(args[i], topLevel); | |
| 370 | + } | |
| 371 | + return res; | |
| 372 | + } | |
| 373 | + | |
| 374 | + Object unwrapReturnValue(Object result) { | |
| 375 | + if (result instanceof Wrapper) { | |
| 376 | + result = ( (Wrapper) result).unwrap(); | |
| 377 | + } | |
| 378 | + | |
| 379 | + return result instanceof Undefined ? null : result; | |
| 380 | + } | |
| 381 | + | |
| 382 | + /* | |
| 383 | + public static void main(String[] args) throws Exception { | |
| 384 | + if (args.length == 0) { | |
| 385 | + System.out.println("No file specified"); | |
| 386 | + return; | |
| 387 | + } | |
| 388 | + | |
| 389 | + InputStreamReader r = new InputStreamReader(new FileInputStream(args[0])); | |
| 390 | + ScriptEngine engine = new RhinoScriptEngine(); | |
| 391 | + | |
| 392 | + engine.put("x", "y"); | |
| 393 | + engine.put(ScriptEngine.FILENAME, args[0]); | |
| 394 | + engine.eval(r); | |
| 395 | + System.out.println(engine.get("x")); | |
| 396 | + } | |
| 397 | + */ | |
| 398 | +} | |
| @@ -0,0 +1,163 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package com.sun.script.javascript; | |
| 27 | +import javax.script.*; | |
| 28 | +import java.util.*; | |
| 29 | +import sun.org.mozilla.javascript.internal.*; | |
| 30 | +import com.sun.script.util.*; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * Factory to create RhinoScriptEngine | |
| 34 | + * | |
| 35 | + * @author Mike Grogan | |
| 36 | + * @since 1.6 | |
| 37 | + */ | |
| 38 | +public class RhinoScriptEngineFactory extends ScriptEngineFactoryBase { | |
| 39 | + | |
| 40 | + public RhinoScriptEngineFactory() { | |
| 41 | + } | |
| 42 | + | |
| 43 | + public List<String> getExtensions() { | |
| 44 | + return extensions; | |
| 45 | + } | |
| 46 | + | |
| 47 | + public List<String> getMimeTypes() { | |
| 48 | + return mimeTypes; | |
| 49 | + } | |
| 50 | + | |
| 51 | + public List<String> getNames() { | |
| 52 | + return names; | |
| 53 | + } | |
| 54 | + | |
| 55 | + public Object getParameter(String key) { | |
| 56 | + if (key.equals(ScriptEngine.NAME)) { | |
| 57 | + return "javascript"; | |
| 58 | + } else if (key.equals(ScriptEngine.ENGINE)) { | |
| 59 | + return "Mozilla Rhino"; | |
| 60 | + } else if (key.equals(ScriptEngine.ENGINE_VERSION)) { | |
| 61 | + return "1.7 release 3 PRERELEASE"; | |
| 62 | + } else if (key.equals(ScriptEngine.LANGUAGE)) { | |
| 63 | + return "ECMAScript"; | |
| 64 | + } else if (key.equals(ScriptEngine.LANGUAGE_VERSION)) { | |
| 65 | + return "1.8"; | |
| 66 | + } else if (key.equals("THREADING")) { | |
| 67 | + return "MULTITHREADED"; | |
| 68 | + } else { | |
| 69 | + throw new IllegalArgumentException("Invalid key"); | |
| 70 | + } | |
| 71 | + } | |
| 72 | + | |
| 73 | + public ScriptEngine getScriptEngine() { | |
| 74 | + RhinoScriptEngine ret = new RhinoScriptEngine(); | |
| 75 | + ret.setEngineFactory(this); | |
| 76 | + return ret; | |
| 77 | + } | |
| 78 | + | |
| 79 | + public String getMethodCallSyntax(String obj, String method, String... args) { | |
| 80 | + | |
| 81 | + String ret = obj + "." + method + "("; | |
| 82 | + int len = args.length; | |
| 83 | + if (len == 0) { | |
| 84 | + ret += ")"; | |
| 85 | + return ret; | |
| 86 | + } | |
| 87 | + | |
| 88 | + for (int i = 0; i < len; i++) { | |
| 89 | + ret += args[i]; | |
| 90 | + if (i != len - 1) { | |
| 91 | + ret += ","; | |
| 92 | + } else { | |
| 93 | + ret += ")"; | |
| 94 | + } | |
| 95 | + } | |
| 96 | + return ret; | |
| 97 | + } | |
| 98 | + | |
| 99 | + public String getOutputStatement(String toDisplay) { | |
| 100 | + StringBuffer buf = new StringBuffer(); | |
| 101 | + int len = toDisplay.length(); | |
| 102 | + buf.append("print(\""); | |
| 103 | + for (int i = 0; i < len; i++) { | |
| 104 | + char ch = toDisplay.charAt(i); | |
| 105 | + switch (ch) { | |
| 106 | + case '"': | |
| 107 | + buf.append("\\\""); | |
| 108 | + break; | |
| 109 | + case '\\': | |
| 110 | + buf.append("\\\\"); | |
| 111 | + break; | |
| 112 | + default: | |
| 113 | + buf.append(ch); | |
| 114 | + break; | |
| 115 | + } | |
| 116 | + } | |
| 117 | + buf.append("\")"); | |
| 118 | + return buf.toString(); | |
| 119 | + } | |
| 120 | + | |
| 121 | + public String getProgram(String... statements) { | |
| 122 | + int len = statements.length; | |
| 123 | + String ret = ""; | |
| 124 | + for (int i = 0; i < len; i++) { | |
| 125 | + ret += statements[i] + ";"; | |
| 126 | + } | |
| 127 | + | |
| 128 | + return ret; | |
| 129 | + } | |
| 130 | + | |
| 131 | + /* | |
| 132 | + public static void main(String[] args) { | |
| 133 | + RhinoScriptEngineFactory fact = new RhinoScriptEngineFactory(); | |
| 134 | + System.out.println(fact.getParameter(ScriptEngine.ENGINE_VERSION)); | |
| 135 | + } | |
| 136 | + */ | |
| 137 | + | |
| 138 | + private static List<String> names; | |
| 139 | + private static List<String> mimeTypes; | |
| 140 | + private static List<String> extensions; | |
| 141 | + | |
| 142 | + static { | |
| 143 | + names = new ArrayList<String>(6); | |
| 144 | + names.add("js"); | |
| 145 | + names.add("rhino"); | |
| 146 | + names.add("JavaScript"); | |
| 147 | + names.add("javascript"); | |
| 148 | + names.add("ECMAScript"); | |
| 149 | + names.add("ecmascript"); | |
| 150 | + names = Collections.unmodifiableList(names); | |
| 151 | + | |
| 152 | + mimeTypes = new ArrayList<String>(4); | |
| 153 | + mimeTypes.add("application/javascript"); | |
| 154 | + mimeTypes.add("application/ecmascript"); | |
| 155 | + mimeTypes.add("text/javascript"); | |
| 156 | + mimeTypes.add("text/ecmascript"); | |
| 157 | + mimeTypes = Collections.unmodifiableList(mimeTypes); | |
| 158 | + | |
| 159 | + extensions = new ArrayList<String>(1); | |
| 160 | + extensions.add("js"); | |
| 161 | + extensions = Collections.unmodifiableList(extensions); | |
| 162 | + } | |
| 163 | +} | |
| @@ -0,0 +1,156 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package com.sun.script.javascript; | |
| 27 | + | |
| 28 | +import sun.org.mozilla.javascript.internal.*; | |
| 29 | +import javax.script.*; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * This class serves as top level scope for Rhino. This class adds | |
| 33 | + * 3 top level functions (bindings, scope, sync) and two constructors | |
| 34 | + * (JSAdapter, JavaAdapter). | |
| 35 | + * | |
| 36 | + * @author A. Sundararajan | |
| 37 | + * @since 1.6 | |
| 38 | + */ | |
| 39 | +public final class RhinoTopLevel extends ImporterTopLevel { | |
| 40 | + RhinoTopLevel(Context cx, RhinoScriptEngine engine) { | |
| 41 | + super(cx); | |
| 42 | + this.engine = engine; | |
| 43 | + | |
| 44 | + | |
| 45 | + // initialize JSAdapter lazily. Reduces footprint & startup time. | |
| 46 | + new LazilyLoadedCtor(this, "JSAdapter", | |
| 47 | + "com.sun.script.javascript.JSAdapter", | |
| 48 | + false); | |
| 49 | + | |
| 50 | + /* | |
| 51 | + * initialize JavaAdapter. We can't lazy initialize this because | |
| 52 | + * lazy initializer attempts to define a new property. But, JavaAdapter | |
| 53 | + * is an exisiting property that we overwrite. | |
| 54 | + */ | |
| 55 | + JavaAdapter.init(cx, this, false); | |
| 56 | + | |
| 57 | + // add top level functions | |
| 58 | + String names[] = { "bindings", "scope", "sync" }; | |
| 59 | + defineFunctionProperties(names, RhinoTopLevel.class, | |
| 60 | + ScriptableObject.DONTENUM); | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * The bindings function takes a JavaScript scope object | |
| 65 | + * of type ExternalScriptable and returns the underlying Bindings | |
| 66 | + * instance. | |
| 67 | + * | |
| 68 | + * var page = scope(pageBindings); | |
| 69 | + * with (page) { | |
| 70 | + * // code that uses page scope | |
| 71 | + * } | |
| 72 | + * var b = bindings(page); | |
| 73 | + * // operate on bindings here. | |
| 74 | + */ | |
| 75 | + public static Object bindings(Context cx, Scriptable thisObj, Object[] args, | |
| 76 | + Function funObj) { | |
| 77 | + if (args.length == 1) { | |
| 78 | + Object arg = args[0]; | |
| 79 | + if (arg instanceof Wrapper) { | |
| 80 | + arg = ((Wrapper)arg).unwrap(); | |
| 81 | + } | |
| 82 | + if (arg instanceof ExternalScriptable) { | |
| 83 | + ScriptContext ctx = ((ExternalScriptable)arg).getContext(); | |
| 84 | + Bindings bind = ctx.getBindings(ScriptContext.ENGINE_SCOPE); | |
| 85 | + return Context.javaToJS(bind, | |
| 86 | + ScriptableObject.getTopLevelScope(thisObj)); | |
| 87 | + } | |
| 88 | + } | |
| 89 | + return cx.getUndefinedValue(); | |
| 90 | + } | |
| 91 | + | |
| 92 | + /** | |
| 93 | + * The scope function creates a new JavaScript scope object | |
| 94 | + * with given Bindings object as backing store. This can be used | |
| 95 | + * to create a script scope based on arbitrary Bindings instance. | |
| 96 | + * For example, in webapp scenario, a 'page' level Bindings instance | |
| 97 | + * may be wrapped as a scope and code can be run in JavaScripe 'with' | |
| 98 | + * statement: | |
| 99 | + * | |
| 100 | + * var page = scope(pageBindings); | |
| 101 | + * with (page) { | |
| 102 | + * // code that uses page scope | |
| 103 | + * } | |
| 104 | + */ | |
| 105 | + public static Object scope(Context cx, Scriptable thisObj, Object[] args, | |
| 106 | + Function funObj) { | |
| 107 | + if (args.length == 1) { | |
| 108 | + Object arg = args[0]; | |
| 109 | + if (arg instanceof Wrapper) { | |
| 110 | + arg = ((Wrapper)arg).unwrap(); | |
| 111 | + } | |
| 112 | + if (arg instanceof Bindings) { | |
| 113 | + ScriptContext ctx = new SimpleScriptContext(); | |
| 114 | + ctx.setBindings((Bindings)arg, ScriptContext.ENGINE_SCOPE); | |
| 115 | + Scriptable res = new ExternalScriptable(ctx); | |
| 116 | + res.setPrototype(ScriptableObject.getObjectPrototype(thisObj)); | |
| 117 | + res.setParentScope(ScriptableObject.getTopLevelScope(thisObj)); | |
| 118 | + return res; | |
| 119 | + } | |
| 120 | + } | |
| 121 | + return cx.getUndefinedValue(); | |
| 122 | + } | |
| 123 | + | |
| 124 | + /** | |
| 125 | + * The sync function creates a synchronized function (in the sense | |
| 126 | + * of a Java synchronized method) from an existing function. The | |
| 127 | + * new function synchronizes on the <code>this</code> object of | |
| 128 | + * its invocation. | |
| 129 | + * js> var o = { f : sync(function(x) { | |
| 130 | + * print("entry"); | |
| 131 | + * Packages.java.lang.Thread.sleep(x*1000); | |
| 132 | + * print("exit"); | |
| 133 | + * })}; | |
| 134 | + * js> thread(function() {o.f(5);}); | |
| 135 | + * entry | |
| 136 | + * js> thread(function() {o.f(5);}); | |
| 137 | + * js> | |
| 138 | + * exit | |
| 139 | + * entry | |
| 140 | + * exit | |
| 141 | + */ | |
| 142 | + public static Object sync(Context cx, Scriptable thisObj, Object[] args, | |
| 143 | + Function funObj) { | |
| 144 | + if (args.length == 1 && args[0] instanceof Function) { | |
| 145 | + return new Synchronizer((Function)args[0]); | |
| 146 | + } else { | |
| 147 | + throw Context.reportRuntimeError("wrong argument(s) for sync"); | |
| 148 | + } | |
| 149 | + } | |
| 150 | + | |
| 151 | + RhinoScriptEngine getScriptEngine() { | |
| 152 | + return engine; | |
| 153 | + } | |
| 154 | + | |
| 155 | + private RhinoScriptEngine engine; | |
| 156 | +} | |
| @@ -0,0 +1,148 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package com.sun.script.javascript; | |
| 27 | + | |
| 28 | +import java.lang.reflect.*; | |
| 29 | +import static sun.security.util.SecurityConstants.*; | |
| 30 | +import sun.org.mozilla.javascript.internal.*; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * This wrap factory is used for security reasons. JSR 223 script | |
| 34 | + * engine interface and JavaScript engine classes are run as bootstrap | |
| 35 | + * classes. For example, java.lang.Class.forName method (when called without | |
| 36 | + * class loader) uses caller's class loader. This may be exploited by script | |
| 37 | + * authors to access classes otherwise not accessible. For example, | |
| 38 | + * classes in sun.* namespace are normally not accessible to untrusted | |
| 39 | + * code and hence should not be accessible to JavaScript run from | |
| 40 | + * untrusted code. | |
| 41 | + * | |
| 42 | + * @author A. Sundararajan | |
| 43 | + * @since 1.6 | |
| 44 | + */ | |
| 45 | +final class RhinoWrapFactory extends WrapFactory { | |
| 46 | + private RhinoWrapFactory() {} | |
| 47 | + private static RhinoWrapFactory theInstance; | |
| 48 | + | |
| 49 | + static synchronized WrapFactory getInstance() { | |
| 50 | + if (theInstance == null) { | |
| 51 | + theInstance = new RhinoWrapFactory(); | |
| 52 | + } | |
| 53 | + return theInstance; | |
| 54 | + } | |
| 55 | + | |
| 56 | + // We use instance of this class to wrap security sensitive | |
| 57 | + // Java object. Please refer below. | |
| 58 | + private static class RhinoJavaObject extends NativeJavaObject { | |
| 59 | + RhinoJavaObject(Scriptable scope, Object obj, Class type) { | |
| 60 | + // we pass 'null' to object. NativeJavaObject uses | |
| 61 | + // passed 'type' to reflect fields and methods when | |
| 62 | + // object is null. | |
| 63 | + super(scope, null, type); | |
| 64 | + | |
| 65 | + // Now, we set actual object. 'javaObject' is protected | |
| 66 | + // field of NativeJavaObject. | |
| 67 | + javaObject = obj; | |
| 68 | + } | |
| 69 | + } | |
| 70 | + | |
| 71 | + public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, | |
| 72 | + Object javaObject, Class staticType) { | |
| 73 | + SecurityManager sm = System.getSecurityManager(); | |
| 74 | + ClassShutter classShutter = RhinoClassShutter.getInstance(); | |
| 75 | + if (javaObject instanceof ClassLoader) { | |
| 76 | + // Check with Security Manager whether we can expose a | |
| 77 | + // ClassLoader... | |
| 78 | + if (sm != null) { | |
| 79 | + sm.checkPermission(GET_CLASSLOADER_PERMISSION); | |
| 80 | + } | |
| 81 | + // if we fall through here, check permission succeeded. | |
| 82 | + return super.wrapAsJavaObject(cx, scope, javaObject, staticType); | |
| 83 | + } else { | |
| 84 | + String name = null; | |
| 85 | + if (javaObject instanceof Class) { | |
| 86 | + name = ((Class)javaObject).getName(); | |
| 87 | + } else if (javaObject instanceof Member) { | |
| 88 | + Member member = (Member) javaObject; | |
| 89 | + // Check member access. Don't allow reflective access to | |
| 90 | + // non-public members. Note that we can't call checkMemberAccess | |
| 91 | + // because that expects exact stack depth! | |
| 92 | + if (sm != null && !Modifier.isPublic(member.getModifiers())) { | |
| 93 | + return null; | |
| 94 | + } | |
| 95 | + name = member.getDeclaringClass().getName(); | |
| 96 | + } | |
| 97 | + // Now, make sure that no ClassShutter prevented Class or Member | |
| 98 | + // of it is accessed reflectively. Note that ClassShutter may | |
| 99 | + // prevent access to a class, even though SecurityManager permit. | |
| 100 | + if (name != null) { | |
| 101 | + if (!classShutter.visibleToScripts(name)) { | |
| 102 | + return null; | |
| 103 | + } else { | |
| 104 | + return super.wrapAsJavaObject(cx, scope, javaObject, staticType); | |
| 105 | + } | |
| 106 | + } | |
| 107 | + } | |
| 108 | + | |
| 109 | + // we have got some non-reflective object. | |
| 110 | + Class dynamicType = javaObject.getClass(); | |
| 111 | + String name = dynamicType.getName(); | |
| 112 | + if (!classShutter.visibleToScripts(name)) { | |
| 113 | + // Object of some sensitive class (such as sun.net.www.* | |
| 114 | + // objects returned from public method of java.net.URL class. | |
| 115 | + // We expose this object as though it is an object of some | |
| 116 | + // super class that is safe for access. | |
| 117 | + | |
| 118 | + Class type = null; | |
| 119 | + | |
| 120 | + // Whenever a Java Object is wrapped, we are passed with a | |
| 121 | + // staticType which is the type found from environment. For | |
| 122 | + // example, method return type known from signature. The dynamic | |
| 123 | + // type would be the actual Class of the actual returned object. | |
| 124 | + // If the staticType is an interface, we just use that type. | |
| 125 | + if (staticType != null && staticType.isInterface()) { | |
| 126 | + type = staticType; | |
| 127 | + } else { | |
| 128 | + // dynamicType is always a class type and never an interface. | |
| 129 | + // find an accessible super class of the dynamic type. | |
| 130 | + while (dynamicType != null) { | |
| 131 | + dynamicType = dynamicType.getSuperclass(); | |
| 132 | + name = dynamicType.getName(); | |
| 133 | + if (classShutter.visibleToScripts(name)) { | |
| 134 | + type = dynamicType; break; | |
| 135 | + } | |
| 136 | + } | |
| 137 | + // atleast java.lang.Object has to be accessible. So, when | |
| 138 | + // we reach here, type variable should not be null. | |
| 139 | + assert type != null: | |
| 140 | + "even java.lang.Object is not accessible?"; | |
| 141 | + } | |
| 142 | + // create custom wrapper with the 'safe' type. | |
| 143 | + return new RhinoJavaObject(scope, javaObject, type); | |
| 144 | + } else { | |
| 145 | + return super.wrapAsJavaObject(cx, scope, javaObject, staticType); | |
| 146 | + } | |
| 147 | + } | |
| 148 | +} | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +<../../../../../../mkconfig | |
| 2 | + | |
| 3 | +DIRS=\ | |
| 4 | + META-INF\ | |
| 5 | + | |
| 6 | +TARG=\ | |
| 7 | + ExternalScriptable.dis\ | |
| 8 | + JavaAdapter.dis\ | |
| 9 | + JSAdapter.dis\ | |
| 10 | + RhinoClassShutter.dis\ | |
| 11 | + RhinoCompiledScript.dis\ | |
| 12 | + RhinoScriptEngine.dis\ | |
| 13 | + RhinoScriptEngineFactory.dis\ | |
| 14 | + RhinoTopLevel.dis\ | |
| 15 | + RhinoWrapFactory.dis\ | |
| 16 | + | |
| 17 | +DISBIN=$ROOT/java/dis/java/java/com/sun/script/javascript | |
| 18 | + | |
| 19 | +<$ROOT/mkfiles/mkjava | |
| 20 | +<$ROOT/mkfiles/mksubdirs | |