History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/script/javascript/JSAdapter.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/script/javascript/JSAdapter.java+338−0
@@ -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+}