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 jdk.nashorn.api.scripting;
27
28 import java.security.AccessControlContext;
29 import java.security.AccessController;
30 import java.security.Permissions;
31 import java.security.PrivilegedAction;
32 import java.security.ProtectionDomain;
33 import java.util.AbstractMap;
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.Iterator;
38 import java.util.LinkedHashSet;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42 import java.util.concurrent.Callable;
43 import javax.script.Bindings;
44 import jdk.nashorn.internal.runtime.ConsString;
45 import jdk.nashorn.internal.runtime.Context;
46 import jdk.nashorn.internal.runtime.GlobalObject;
47 import jdk.nashorn.internal.runtime.JSType;
48 import jdk.nashorn.internal.runtime.ScriptFunction;
49 import jdk.nashorn.internal.runtime.ScriptObject;
50 import jdk.nashorn.internal.runtime.ScriptRuntime;
51
52 /**
53 * Mirror object that wraps a given Nashorn Script object.
54 */
55 public final class ScriptObjectMirror extends AbstractJSObject implements Bindings {
56 private static AccessControlContext getContextAccCtxt() {
57 final Permissions perms = new Permissions();
58 perms.add(new RuntimePermission(Context.NASHORN_GET_CONTEXT));
59 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
60 }
61
62 private static final AccessControlContext GET_CONTEXT_ACC_CTXT = getContextAccCtxt();
63
64 private final ScriptObject sobj;
65 private final ScriptObject global;
66 private final boolean strict;
67
68 @Override
69 public boolean equals(final Object other) {
70 if (other instanceof ScriptObjectMirror) {
71 return sobj.equals(((ScriptObjectMirror)other).sobj);
72 }
73
74 return false;
75 }
76
77 @Override
78 public int hashCode() {
79 return sobj.hashCode();
80 }
81
82 @Override
83 public String toString() {
84 return inGlobal(new Callable<String>() {
85 @Override
86 public String call() {
87 return ScriptRuntime.safeToString(sobj);
88 }
89 });
90 }
91
92 // JSObject methods
93
94 @Override
95 public Object call(final Object thiz, final Object... args) {
96 final ScriptObject oldGlobal = Context.getGlobal();
97 final boolean globalChanged = (oldGlobal != global);
98
99 try {
100 if (globalChanged) {
101 Context.setGlobal(global);
102 }
103
104 if (sobj instanceof ScriptFunction) {
105 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
106 final Object self = globalChanged? wrap(thiz, oldGlobal) : thiz;
107 return wrap(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)), global);
108 }
109
110 throw new RuntimeException("not a function: " + toString());
111 } catch (final RuntimeException | Error e) {
112 throw e;
113 } catch (final Throwable t) {
114 throw new RuntimeException(t);
115 } finally {
116 if (globalChanged) {
117 Context.setGlobal(oldGlobal);
118 }
119 }
120 }
121
122 @Override
123 public Object newObject(final Object... args) {
124 final ScriptObject oldGlobal = Context.getGlobal();
125 final boolean globalChanged = (oldGlobal != global);
126
127 try {
128 if (globalChanged) {
129 Context.setGlobal(global);
130 }
131
132 if (sobj instanceof ScriptFunction) {
133 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
134 return wrap(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)), global);
135 }
136
137 throw new RuntimeException("not a constructor: " + toString());
138 } catch (final RuntimeException | Error e) {
139 throw e;
140 } catch (final Throwable t) {
141 throw new RuntimeException(t);
142 } finally {
143 if (globalChanged) {
144 Context.setGlobal(oldGlobal);
145 }
146 }
147 }
148
149 @Override
150 public Object eval(final String s) {
151 return inGlobal(new Callable<Object>() {
152 @Override
153 public Object call() {
154 final Context context = AccessController.doPrivileged(
155 new PrivilegedAction<Context>() {
156 @Override
157 public Context run() {
158 return Context.getContext();
159 }
160 }, GET_CONTEXT_ACC_CTXT);
161 return wrap(context.eval(global, s, null, null, false), global);
162 }
163 });
164 }
165
166 public Object callMember(final String functionName, final Object... args) {
167 functionName.getClass(); // null check
168 final ScriptObject oldGlobal = Context.getGlobal();
169 final boolean globalChanged = (oldGlobal != global);
170
171 try {
172 if (globalChanged) {
173 Context.setGlobal(global);
174 }
175
176 final Object val = sobj.get(functionName);
177 if (val instanceof ScriptFunction) {
178 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
179 return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
180 } else if (val instanceof JSObject && ((JSObject)val).isFunction()) {
181 return ((JSObject)val).call(sobj, args);
182 }
183
184 throw new NoSuchMethodException("No such function " + functionName);
185 } catch (final RuntimeException | Error e) {
186 throw e;
187 } catch (final Throwable t) {
188 throw new RuntimeException(t);
189 } finally {
190 if (globalChanged) {
191 Context.setGlobal(oldGlobal);
192 }
193 }
194 }
195
196 @Override
197 public Object getMember(final String name) {
198 name.getClass();
199 return inGlobal(new Callable<Object>() {
200 @Override public Object call() {
201 return wrap(sobj.get(name), global);
202 }
203 });
204 }
236 name.getClass();
237 remove(name);
238 }
239
240 @Override
241 public void setMember(final String name, final Object value) {
242 name.getClass();
243 put(name, value);
244 }
245
246 @Override
247 public void setSlot(final int index, final Object value) {
248 inGlobal(new Callable<Void>() {
249 @Override public Void call() {
250 sobj.set(index, unwrap(value, global), strict);
251 return null;
252 }
253 });
254 }
255
256 @Override
257 public boolean isInstance(final Object obj) {
258 if (! (obj instanceof ScriptObjectMirror)) {
259 return false;
260 }
261
262 final ScriptObjectMirror instance = (ScriptObjectMirror)obj;
263 // if not belongs to my global scope, return false
264 if (global != instance.global) {
265 return false;
266 }
267
268 return inGlobal(new Callable<Boolean>() {
269 @Override public Boolean call() {
270 return sobj.isInstance(instance.sobj);
271 }
272 });
273 }
274
275 @Override
601 * @return converted object
602 */
603 public <T> T to(final Class<T> type) {
604 return inGlobal(new Callable<T>() {
605 @Override
606 public T call() {
607 return type.cast(ScriptUtils.convert(sobj, type));
608 }
609 });
610 }
611
612 /**
613 * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
614 *
615 * @param obj object to be wrapped/converted
616 * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
617 * @return wrapped/converted object
618 */
619 public static Object wrap(final Object obj, final Object homeGlobal) {
620 if(obj instanceof ScriptObject) {
621 return homeGlobal instanceof ScriptObject ? new ScriptObjectMirror((ScriptObject)obj, (ScriptObject)homeGlobal) : obj;
622 }
623 if(obj instanceof ConsString) {
624 return obj.toString();
625 }
626 return obj;
627 }
628
629 /**
630 * Unwrap a script object mirror if needed.
631 *
632 * @param obj object to be unwrapped
633 * @param homeGlobal global to which this object belongs
634 * @return unwrapped object
635 */
636 public static Object unwrap(final Object obj, final Object homeGlobal) {
637 if (obj instanceof ScriptObjectMirror) {
638 final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
639 return (mirror.global == homeGlobal)? mirror.sobj : obj;
640 }
641
669 * @param args array to be unwrapped
670 * @param homeGlobal global to which this object belongs
671 * @return unwrapped array
672 */
673 public static Object[] unwrapArray(final Object[] args, final Object homeGlobal) {
674 if (args == null || args.length == 0) {
675 return args;
676 }
677
678 final Object[] newArgs = new Object[args.length];
679 int index = 0;
680 for (final Object obj : args) {
681 newArgs[index] = unwrap(obj, homeGlobal);
682 index++;
683 }
684 return newArgs;
685 }
686
687 // package-privates below this.
688
689 ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
690 assert sobj != null : "ScriptObjectMirror on null!";
691 assert global instanceof GlobalObject : "global is not a GlobalObject";
692
693 this.sobj = sobj;
694 this.global = global;
695 this.strict = ((GlobalObject)global).isStrictContext();
696 }
697
698 // accessors for script engine
699 ScriptObject getScriptObject() {
700 return sobj;
701 }
702
703 ScriptObject getHomeGlobal() {
704 return global;
705 }
706
707 static Object translateUndefined(Object obj) {
708 return (obj == ScriptRuntime.UNDEFINED)? null : obj;
709 }
710
711 // internals only below this.
712 private <V> V inGlobal(final Callable<V> callable) {
713 final ScriptObject oldGlobal = Context.getGlobal();
714 final boolean globalChanged = (oldGlobal != global);
715 if (globalChanged) {
716 Context.setGlobal(global);
717 }
718 try {
719 return callable.call();
720 } catch (final RuntimeException e) {
721 throw e;
722 } catch (final Exception e) {
723 throw new AssertionError("Cannot happen", e);
724 } finally {
725 if (globalChanged) {
726 Context.setGlobal(oldGlobal);
727 }
728 }
729 }
730
731 @Override
732 public double toNumber() {
733 return inGlobal(new Callable<Double>() {
734 @Override public Double call() {
735 return JSType.toNumber(sobj);
736 }
737 });
738 }
739 }
|
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 jdk.nashorn.api.scripting;
27
28 import java.nio.ByteBuffer;
29 import java.security.AccessControlContext;
30 import java.security.AccessController;
31 import java.security.Permissions;
32 import java.security.PrivilegedAction;
33 import java.security.ProtectionDomain;
34 import java.util.AbstractMap;
35 import java.util.ArrayList;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.Iterator;
39 import java.util.LinkedHashSet;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.concurrent.Callable;
44 import javax.script.Bindings;
45 import jdk.nashorn.internal.objects.Global;
46 import jdk.nashorn.internal.runtime.arrays.ArrayData;
47 import jdk.nashorn.internal.runtime.ConsString;
48 import jdk.nashorn.internal.runtime.Context;
49 import jdk.nashorn.internal.runtime.JSType;
50 import jdk.nashorn.internal.runtime.ScriptFunction;
51 import jdk.nashorn.internal.runtime.ScriptObject;
52 import jdk.nashorn.internal.runtime.ScriptRuntime;
53
54 /**
55 * Mirror object that wraps a given Nashorn Script object.
56 */
57 public final class ScriptObjectMirror extends AbstractJSObject implements Bindings {
58 private static AccessControlContext getContextAccCtxt() {
59 final Permissions perms = new Permissions();
60 perms.add(new RuntimePermission(Context.NASHORN_GET_CONTEXT));
61 return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
62 }
63
64 private static final AccessControlContext GET_CONTEXT_ACC_CTXT = getContextAccCtxt();
65
66 private final ScriptObject sobj;
67 private final Global global;
68 private final boolean strict;
69
70 @Override
71 public boolean equals(final Object other) {
72 if (other instanceof ScriptObjectMirror) {
73 return sobj.equals(((ScriptObjectMirror)other).sobj);
74 }
75
76 return false;
77 }
78
79 @Override
80 public int hashCode() {
81 return sobj.hashCode();
82 }
83
84 @Override
85 public String toString() {
86 return inGlobal(new Callable<String>() {
87 @Override
88 public String call() {
89 return ScriptRuntime.safeToString(sobj);
90 }
91 });
92 }
93
94 // JSObject methods
95
96 @Override
97 public Object call(final Object thiz, final Object... args) {
98 final Global oldGlobal = Context.getGlobal();
99 final boolean globalChanged = (oldGlobal != global);
100
101 try {
102 if (globalChanged) {
103 Context.setGlobal(global);
104 }
105
106 if (sobj instanceof ScriptFunction) {
107 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
108 final Object self = globalChanged? wrap(thiz, oldGlobal) : thiz;
109 return wrap(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)), global);
110 }
111
112 throw new RuntimeException("not a function: " + toString());
113 } catch (final NashornException ne) {
114 throw ne.initEcmaError(global);
115 } catch (final RuntimeException | Error e) {
116 throw e;
117 } catch (final Throwable t) {
118 throw new RuntimeException(t);
119 } finally {
120 if (globalChanged) {
121 Context.setGlobal(oldGlobal);
122 }
123 }
124 }
125
126 @Override
127 public Object newObject(final Object... args) {
128 final Global oldGlobal = Context.getGlobal();
129 final boolean globalChanged = (oldGlobal != global);
130
131 try {
132 if (globalChanged) {
133 Context.setGlobal(global);
134 }
135
136 if (sobj instanceof ScriptFunction) {
137 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
138 return wrap(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)), global);
139 }
140
141 throw new RuntimeException("not a constructor: " + toString());
142 } catch (final NashornException ne) {
143 throw ne.initEcmaError(global);
144 } catch (final RuntimeException | Error e) {
145 throw e;
146 } catch (final Throwable t) {
147 throw new RuntimeException(t);
148 } finally {
149 if (globalChanged) {
150 Context.setGlobal(oldGlobal);
151 }
152 }
153 }
154
155 @Override
156 public Object eval(final String s) {
157 return inGlobal(new Callable<Object>() {
158 @Override
159 public Object call() {
160 final Context context = AccessController.doPrivileged(
161 new PrivilegedAction<Context>() {
162 @Override
163 public Context run() {
164 return Context.getContext();
165 }
166 }, GET_CONTEXT_ACC_CTXT);
167 return wrap(context.eval(global, s, null, null, false), global);
168 }
169 });
170 }
171
172 public Object callMember(final String functionName, final Object... args) {
173 functionName.getClass(); // null check
174 final Global oldGlobal = Context.getGlobal();
175 final boolean globalChanged = (oldGlobal != global);
176
177 try {
178 if (globalChanged) {
179 Context.setGlobal(global);
180 }
181
182 final Object val = sobj.get(functionName);
183 if (val instanceof ScriptFunction) {
184 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
185 return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
186 } else if (val instanceof JSObject && ((JSObject)val).isFunction()) {
187 return ((JSObject)val).call(sobj, args);
188 }
189
190 throw new NoSuchMethodException("No such function " + functionName);
191 } catch (final NashornException ne) {
192 throw ne.initEcmaError(global);
193 } catch (final RuntimeException | Error e) {
194 throw e;
195 } catch (final Throwable t) {
196 throw new RuntimeException(t);
197 } finally {
198 if (globalChanged) {
199 Context.setGlobal(oldGlobal);
200 }
201 }
202 }
203
204 @Override
205 public Object getMember(final String name) {
206 name.getClass();
207 return inGlobal(new Callable<Object>() {
208 @Override public Object call() {
209 return wrap(sobj.get(name), global);
210 }
211 });
212 }
244 name.getClass();
245 remove(name);
246 }
247
248 @Override
249 public void setMember(final String name, final Object value) {
250 name.getClass();
251 put(name, value);
252 }
253
254 @Override
255 public void setSlot(final int index, final Object value) {
256 inGlobal(new Callable<Void>() {
257 @Override public Void call() {
258 sobj.set(index, unwrap(value, global), strict);
259 return null;
260 }
261 });
262 }
263
264 /**
265 * Nashorn extension: setIndexedPropertiesToExternalArrayData.
266 * set indexed properties be exposed from a given nio ByteBuffer.
267 *
268 * @param buf external buffer - should be a nio ByteBuffer
269 */
270 public void setIndexedPropertiesToExternalArrayData(final ByteBuffer buf) {
271 inGlobal(new Callable<Void>() {
272 @Override public Void call() {
273 sobj.setArray(ArrayData.allocate(buf));
274 return null;
275 }
276 });
277 }
278
279
280 @Override
281 public boolean isInstance(final Object obj) {
282 if (! (obj instanceof ScriptObjectMirror)) {
283 return false;
284 }
285
286 final ScriptObjectMirror instance = (ScriptObjectMirror)obj;
287 // if not belongs to my global scope, return false
288 if (global != instance.global) {
289 return false;
290 }
291
292 return inGlobal(new Callable<Boolean>() {
293 @Override public Boolean call() {
294 return sobj.isInstance(instance.sobj);
295 }
296 });
297 }
298
299 @Override
625 * @return converted object
626 */
627 public <T> T to(final Class<T> type) {
628 return inGlobal(new Callable<T>() {
629 @Override
630 public T call() {
631 return type.cast(ScriptUtils.convert(sobj, type));
632 }
633 });
634 }
635
636 /**
637 * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
638 *
639 * @param obj object to be wrapped/converted
640 * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
641 * @return wrapped/converted object
642 */
643 public static Object wrap(final Object obj, final Object homeGlobal) {
644 if(obj instanceof ScriptObject) {
645 return homeGlobal instanceof Global ? new ScriptObjectMirror((ScriptObject)obj, (Global)homeGlobal) : obj;
646 }
647 if(obj instanceof ConsString) {
648 return obj.toString();
649 }
650 return obj;
651 }
652
653 /**
654 * Unwrap a script object mirror if needed.
655 *
656 * @param obj object to be unwrapped
657 * @param homeGlobal global to which this object belongs
658 * @return unwrapped object
659 */
660 public static Object unwrap(final Object obj, final Object homeGlobal) {
661 if (obj instanceof ScriptObjectMirror) {
662 final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
663 return (mirror.global == homeGlobal)? mirror.sobj : obj;
664 }
665
693 * @param args array to be unwrapped
694 * @param homeGlobal global to which this object belongs
695 * @return unwrapped array
696 */
697 public static Object[] unwrapArray(final Object[] args, final Object homeGlobal) {
698 if (args == null || args.length == 0) {
699 return args;
700 }
701
702 final Object[] newArgs = new Object[args.length];
703 int index = 0;
704 for (final Object obj : args) {
705 newArgs[index] = unwrap(obj, homeGlobal);
706 index++;
707 }
708 return newArgs;
709 }
710
711 // package-privates below this.
712
713 ScriptObjectMirror(final ScriptObject sobj, final Global global) {
714 assert sobj != null : "ScriptObjectMirror on null!";
715 assert global != null : "home Global is null";
716
717 this.sobj = sobj;
718 this.global = global;
719 this.strict = global.isStrictContext();
720 }
721
722 // accessors for script engine
723 ScriptObject getScriptObject() {
724 return sobj;
725 }
726
727 Global getHomeGlobal() {
728 return global;
729 }
730
731 static Object translateUndefined(Object obj) {
732 return (obj == ScriptRuntime.UNDEFINED)? null : obj;
733 }
734
735 // internals only below this.
736 private <V> V inGlobal(final Callable<V> callable) {
737 final Global oldGlobal = Context.getGlobal();
738 final boolean globalChanged = (oldGlobal != global);
739 if (globalChanged) {
740 Context.setGlobal(global);
741 }
742 try {
743 return callable.call();
744 } catch (final NashornException ne) {
745 throw ne.initEcmaError(global);
746 } catch (final RuntimeException e) {
747 throw e;
748 } catch (final Exception e) {
749 throw new AssertionError("Cannot happen", e);
750 } finally {
751 if (globalChanged) {
752 Context.setGlobal(oldGlobal);
753 }
754 }
755 }
756
757 @Override
758 public double toNumber() {
759 return inGlobal(new Callable<Double>() {
760 @Override public Double call() {
761 return JSType.toNumber(sobj);
762 }
763 });
764 }
765 }
|