public static JaggeryContext clonedJaggeryContext(ServletContext context) { JaggeryContext shared = sharedJaggeryContext(context); RhinoEngine engine = shared.getEngine(); Scriptable sharedScope = shared.getScope(); Context cx = Context.getCurrentContext(); ScriptableObject instanceScope = (ScriptableObject) cx.newObject(sharedScope); instanceScope.setPrototype(sharedScope); instanceScope.setParentScope(null); JaggeryContext clone = new JaggeryContext(); clone.setEngine(engine); clone.setTenantId(shared.getTenantId()); clone.setScope(instanceScope); clone.addProperty(Constants.SERVLET_CONTEXT, shared.getProperty(Constants.SERVLET_CONTEXT)); clone.addProperty(LogHostObject.LOG_LEVEL, shared.getProperty(LogHostObject.LOG_LEVEL)); clone.addProperty( FileHostObject.JAVASCRIPT_FILE_MANAGER, shared.getProperty(FileHostObject.JAVASCRIPT_FILE_MANAGER)); clone.addProperty( Constants.JAGGERY_CORE_MANAGER, shared.getProperty(Constants.JAGGERY_CORE_MANAGER)); clone.addProperty(Constants.JAGGERY_INCLUDED_SCRIPTS, new HashMap<String, Boolean>()); clone.addProperty(Constants.JAGGERY_INCLUDES_CALLSTACK, new Stack<String>()); clone.addProperty(Constants.JAGGERY_REQUIRED_MODULES, new HashMap<String, ScriptableObject>()); CommonManager.setJaggeryContext(clone); return clone; }
public static ScriptableObject require( Context cx, Scriptable thisObj, Object[] args, Function funObj) throws ScriptException, IOException { String functionName = "require"; int argsCount = args.length; if (argsCount != 1) { HostObjectUtil.invalidNumberOfArgs( CommonManager.HOST_OBJECT_NAME, functionName, argsCount, false); } if (!(args[0] instanceof String)) { HostObjectUtil.invalidArgsError( CommonManager.HOST_OBJECT_NAME, functionName, "1", "string", args[0], false); } String moduleId = (String) args[0]; int dotIndex = moduleId.lastIndexOf("."); if (moduleId.length() == dotIndex + 1) { String msg = "Invalid file path for require method : " + moduleId; log.error(msg); throw new ScriptException(msg); } JaggeryContext jaggeryContext = CommonManager.getJaggeryContext(); Map<String, ScriptableObject> requiredModules = (Map<String, ScriptableObject>) jaggeryContext.getProperty(Constants.JAGGERY_REQUIRED_MODULES); ScriptableObject object = requiredModules.get(moduleId); if (object != null) { return object; } if (dotIndex == -1) { object = CommonManager.require(cx, thisObj, args, funObj); initModule(cx, jaggeryContext, moduleId, object); } else { object = (ScriptableObject) cx.newObject(thisObj); object.setPrototype(thisObj); object.setParentScope(null); String ext = moduleId.substring(dotIndex + 1); if (ext.equalsIgnoreCase("json")) { object = executeScript(jaggeryContext, object, moduleId, true, true, false); } else if (ext.equalsIgnoreCase("js")) { object = executeScript(jaggeryContext, object, moduleId, false, true, false); } else if (ext.equalsIgnoreCase("jag")) { object = executeScript(jaggeryContext, object, moduleId, false, false, false); } else { String msg = "Unsupported file type for require() method : ." + ext; log.error(msg); throw new ScriptException(msg); } } requiredModules.put(moduleId, object); return object; }
@Override public void put(String name, Scriptable start, Object value) { int info = findInstanceIdInfo(name); if (info != 0) { if (start == this && isSealed()) { throw Context.reportRuntimeError1("msg.modify.sealed", name); } int attr = (info >>> 16); if ((attr & READONLY) == 0) { if (start == this) { int id = (info & 0xFFFF); setInstanceIdValue(id, value); } else { start.put(name, start, value); } } return; } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { if (start == this && isSealed()) { throw Context.reportRuntimeError1("msg.modify.sealed", name); } prototypeValues.set(id, start, value); return; } } super.put(name, start, value); }
@Override public void delete(String name) { int info = findInstanceIdInfo(name); if (info != 0) { // Let the super class to throw exceptions for sealed objects if (!isSealed()) { int attr = (info >>> 16); if ((attr & PERMANENT) == 0) { int id = (info & 0xFFFF); setInstanceIdValue(id, NOT_FOUND); } return; } } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { if (!isSealed()) { prototypeValues.delete(id); } return; } } super.delete(name); }
@Override public void defineOwnProperty(Context cx, Object key, ScriptableObject desc) { if (key instanceof String) { String name = (String) key; int info = findInstanceIdInfo(name); if (info != 0) { int id = (info & 0xFFFF); if (isAccessorDescriptor(desc)) { delete(id); // it will be replaced with a slot } else { int attr = (info >>> 16); Object value = getProperty(desc, "value"); setInstanceIdValue(id, value == NOT_FOUND ? Undefined.instance : value); setAttributes(id, applyDescriptorToAttributeBitset(attr, desc)); return; } } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { if (isAccessorDescriptor(desc)) { prototypeValues.delete(id); // it will be replaced with a slot } else { int attr = prototypeValues.getAttributes(id); Object value = getProperty(desc, "value"); prototypeValues.set(id, this, value == NOT_FOUND ? Undefined.instance : value); prototypeValues.setAttributes(id, applyDescriptorToAttributeBitset(attr, desc)); return; } } } } super.defineOwnProperty(cx, key, desc); }
final void setAttributes(int id, int attributes) { ScriptableObject.checkValidAttributes(attributes); ensureId(id); synchronized (this) { attributeArray[id - 1] = (short) attributes; } }
private static ObjToIntMap getObjectFunctionNames(Scriptable obj) { Object[] ids = ScriptableObject.getPropertyIds(obj); ObjToIntMap map = new ObjToIntMap(ids.length); for (int i = 0; i != ids.length; ++i) { if (!(ids[i] instanceof String)) continue; String id = (String) ids[i]; Object value = ScriptableObject.getProperty(obj, id); if (value instanceof Function) { Function f = (Function) value; int length = ScriptRuntime.toInt32(ScriptableObject.getProperty(f, "length")); if (length < 0) { length = 0; } map.put(id, length); } } return map; }
static Object lookupQualifiedName(Scriptable scope, String qualifiedName) { StringTokenizer st = new StringTokenizer(qualifiedName, "."); Object result = scope; while (st.hasMoreTokens()) { String s = st.nextToken(); result = ScriptableObject.getProperty((Scriptable) result, s); if (result == null || !(result instanceof Scriptable)) break; } return result; }
@Override public void setAttributes(String name, int attributes) { ScriptableObject.checkValidAttributes(attributes); int info = findInstanceIdInfo(name); if (info != 0) { int currentAttributes = (info >>> 16); if (attributes != currentAttributes) { throw new RuntimeException("Change of attributes for this id is not supported"); } return; } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { prototypeValues.setAttributes(id, attributes); return; } } super.setAttributes(name, attributes); }
public static Function getFunction(Scriptable obj, String functionName) { Object x = ScriptableObject.getProperty(obj, functionName); if (x == Scriptable.NOT_FOUND) { // This method used to swallow the exception from calling // an undefined method. People have come to depend on this // somewhat dubious behavior. It allows people to avoid // implementing listener methods that they don't care about, // for instance. return null; } if (!(x instanceof Function)) throw ScriptRuntime.notFunctionError(x, functionName); return (Function) x; }
final IdFunctionObject createPrecachedConstructor() { if (constructorId != 0) throw new IllegalStateException(); constructorId = obj.findPrototypeId("constructor"); if (constructorId == 0) { throw new IllegalStateException("No id for constructor property"); } obj.initPrototypeId(constructorId); if (constructor == null) { throw new IllegalStateException( obj.getClass().getName() + ".initPrototypeId() did not " + "initialize id=" + constructorId); } constructor.initFunction(obj.getClassName(), ScriptableObject.getTopLevelScope(obj)); constructor.markAsConstructor(obj); return constructor; }
final void initValue(int id, String name, Object value, int attributes) { if (!(1 <= id && id <= maxId)) throw new IllegalArgumentException(); if (name == null) throw new IllegalArgumentException(); if (value == NOT_FOUND) throw new IllegalArgumentException(); ScriptableObject.checkValidAttributes(attributes); if (obj.findPrototypeId(name) != id) throw new IllegalArgumentException(name); if (id == constructorId) { if (!(value instanceof IdFunctionObject)) { throw new IllegalArgumentException( "consructor should be initialized with IdFunctionObject"); } constructor = (IdFunctionObject) value; constructorAttrs = (short) attributes; return; } initSlot(id, name, value, attributes); }
protected final void defaultPut(String name, Object value) { super.put(name, this, value); }
/** Type-munging for field setting and method invocation. Conforms to LC3 specification */ static Object coerceTypeImpl(Class<?> type, Object value) { if (value != null && value.getClass() == type) { return value; } switch (getJSTypeCode(value)) { case JSTYPE_NULL: // raise error if type.isPrimitive() if (type.isPrimitive()) { reportConversionError(value, type); } return null; case JSTYPE_UNDEFINED: if (type == ScriptRuntime.StringClass || type == ScriptRuntime.ObjectClass) { return "undefined"; } else { reportConversionError("undefined", type); } break; case JSTYPE_BOOLEAN: // Under LC3, only JS Booleans can be coerced into a Boolean value if (type == Boolean.TYPE || type == ScriptRuntime.BooleanClass || type == ScriptRuntime.ObjectClass) { return value; } else if (type == ScriptRuntime.StringClass) { return value.toString(); } else { reportConversionError(value, type); } break; case JSTYPE_NUMBER: if (type == ScriptRuntime.StringClass) { return ScriptRuntime.toString(value); } else if (type == ScriptRuntime.ObjectClass) { return coerceToNumber(Double.TYPE, value); } else if ((type.isPrimitive() && type != Boolean.TYPE) || ScriptRuntime.NumberClass.isAssignableFrom(type)) { return coerceToNumber(type, value); } else { reportConversionError(value, type); } break; case JSTYPE_STRING: if (type == ScriptRuntime.StringClass || type.isInstance(value)) { return value; } else if (type == Character.TYPE || type == ScriptRuntime.CharacterClass) { // Special case for converting a single char string to a // character // Placed here because it applies *only* to JS strings, // not other JS objects converted to strings if (((String) value).length() == 1) { return new Character(((String) value).charAt(0)); } else { return coerceToNumber(type, value); } } else if ((type.isPrimitive() && type != Boolean.TYPE) || ScriptRuntime.NumberClass.isAssignableFrom(type)) { return coerceToNumber(type, value); } else { reportConversionError(value, type); } break; case JSTYPE_JAVA_CLASS: if (value instanceof Wrapper) { value = ((Wrapper) value).unwrap(); } if (type == ScriptRuntime.ClassClass || type == ScriptRuntime.ObjectClass) { return value; } else if (type == ScriptRuntime.StringClass) { return value.toString(); } else { reportConversionError(value, type); } break; case JSTYPE_JAVA_OBJECT: case JSTYPE_JAVA_ARRAY: if (value instanceof Wrapper) { value = ((Wrapper) value).unwrap(); } if (type.isPrimitive()) { if (type == Boolean.TYPE) { reportConversionError(value, type); } return coerceToNumber(type, value); } else { if (type == ScriptRuntime.StringClass) { return value.toString(); } else { if (type.isInstance(value)) { return value; } else { reportConversionError(value, type); } } } break; case JSTYPE_OBJECT: if (type == ScriptRuntime.StringClass) { return ScriptRuntime.toString(value); } else if (type.isPrimitive()) { if (type == Boolean.TYPE) { reportConversionError(value, type); } return coerceToNumber(type, value); } else if (type.isInstance(value)) { return value; } else if (type == ScriptRuntime.DateClass && value instanceof NativeDate) { double time = ((NativeDate) value).getJSTimeValue(); // XXX: This will replace NaN by 0 return new Date((long) time); } else if (type.isArray() && value instanceof NativeArray) { // Make a new java array, and coerce the JS array components // to the target (component) type. NativeArray array = (NativeArray) value; long length = array.getLength(); Class<?> arrayType = type.getComponentType(); Object Result = Array.newInstance(arrayType, (int) length); for (int i = 0; i < length; ++i) { try { Array.set(Result, i, coerceType(arrayType, array.get(i, array))); } catch (EvaluatorException ee) { reportConversionError(value, type); } } return Result; } else if (value instanceof Wrapper) { value = ((Wrapper) value).unwrap(); if (type.isInstance(value)) return value; reportConversionError(value, type); } else if (type.isInterface() && value instanceof Callable) { // Try to use function as implementation of Java interface. // // XXX: Currently only instances of ScriptableObject are // supported since the resulting interface proxies should // be reused next time conversion is made and generic // Callable has no storage for it. Weak references can // address it but for now use this restriction. if (value instanceof ScriptableObject) { ScriptableObject so = (ScriptableObject) value; Object key = Kit.makeHashKeyFromPair(COERCED_INTERFACE_KEY, type); Object old = so.getAssociatedValue(key); if (old != null) { // Function was already wrapped return old; } Context cx = Context.getContext(); Object glue = InterfaceAdapter.create(cx, type, (Callable) value); // Store for later retrival glue = so.associateValue(key, glue); return glue; } reportConversionError(value, type); } else { reportConversionError(value, type); } break; } return value; }
static Object js_createAdapter(Context cx, Scriptable scope, Object[] args) { int N = args.length; if (N == 0) { throw ScriptRuntime.typeError0("msg.adapter.zero.args"); } // Expected arguments: // Any number of NativeJavaClass objects representing the super-class // and/or interfaces to implement, followed by one NativeObject providing // the implementation, followed by any number of arguments to pass on // to the (super-class) constructor. int classCount; for (classCount = 0; classCount < N - 1; classCount++) { Object arg = args[classCount]; // We explicitly test for NativeObject here since checking for // instanceof ScriptableObject or !(instanceof NativeJavaClass) // would fail for a Java class that isn't found in the class path // as NativeJavaPackage extends ScriptableObject. if (arg instanceof NativeObject) { break; } if (!(arg instanceof NativeJavaClass)) { throw ScriptRuntime.typeError2( "msg.not.java.class.arg", String.valueOf(classCount), ScriptRuntime.toString(arg)); } } Class<?> superClass = null; Class<?>[] intfs = new Class[classCount]; int interfaceCount = 0; for (int i = 0; i < classCount; ++i) { Class<?> c = ((NativeJavaClass) args[i]).getClassObject(); if (!c.isInterface()) { if (superClass != null) { throw ScriptRuntime.typeError2("msg.only.one.super", superClass.getName(), c.getName()); } superClass = c; } else { intfs[interfaceCount++] = c; } } if (superClass == null) { superClass = ScriptRuntime.ObjectClass; } Class<?>[] interfaces = new Class[interfaceCount]; System.arraycopy(intfs, 0, interfaces, 0, interfaceCount); // next argument is implementation, must be scriptable Scriptable obj = ScriptableObject.ensureScriptable(args[classCount]); Class<?> adapterClass = getAdapterClass(scope, superClass, interfaces, obj); Object adapter; int argsCount = N - classCount - 1; try { if (argsCount > 0) { // Arguments contain parameters for super-class constructor. // We use the generic Java method lookup logic to find and // invoke the right constructor. Object[] ctorArgs = new Object[argsCount + 2]; ctorArgs[0] = obj; ctorArgs[1] = cx.getFactory(); System.arraycopy(args, classCount + 1, ctorArgs, 2, argsCount); // TODO: cache class wrapper? NativeJavaClass classWrapper = new NativeJavaClass(scope, adapterClass, true); NativeJavaMethod ctors = classWrapper.members.ctors; int index = ctors.findCachedFunction(cx, ctorArgs); if (index < 0) { String sig = NativeJavaMethod.scriptSignature(args); throw Context.reportRuntimeError2("msg.no.java.ctor", adapterClass.getName(), sig); } // Found the constructor, so try invoking it. adapter = NativeJavaClass.constructInternal(ctorArgs, ctors.methods[index]); } else { Class<?>[] ctorParms = {ScriptRuntime.ScriptableClass, ScriptRuntime.ContextFactoryClass}; Object[] ctorArgs = {obj, cx.getFactory()}; adapter = adapterClass.getConstructor(ctorParms).newInstance(ctorArgs); } Object self = getAdapterSelf(adapterClass, adapter); // Return unwrapped JavaAdapter if it implements Scriptable if (self instanceof Wrapper) { Object unwrapped = ((Wrapper) self).unwrap(); if (unwrapped instanceof Scriptable) { if (unwrapped instanceof ScriptableObject) { ScriptRuntime.setObjectProtoAndParent((ScriptableObject) unwrapped, scope); } return unwrapped; } } return self; } catch (Exception ex) { throw Context.throwAsScriptRuntimeEx(ex); } }
protected void addIdFunctionProperty(Scriptable obj, Object tag, int id, String name, int arity) { Scriptable scope = ScriptableObject.getTopLevelScope(obj); IdFunctionObject f = newIdFunction(tag, id, name, arity, scope); f.addAsProperty(obj); }
public final void initPrototypeMethod(Object tag, int id, String name, int arity) { Scriptable scope = ScriptableObject.getTopLevelScope(this); IdFunctionObject f = newIdFunction(tag, id, name, arity, scope); prototypeValues.initValue(id, name, f, DONTENUM); }
public static Scriptable createAdapterWrapper(Scriptable obj, Object adapter) { Scriptable scope = ScriptableObject.getTopLevelScope(obj); NativeJavaObject res = new NativeJavaObject(scope, adapter, null, true); res.setPrototype(obj); return res; }
public Scriptable getPrototype() { if (prototype == null && javaObject instanceof String) { return ScriptableObject.getClassPrototype(parent, "String"); } return prototype; }