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.runtime.arrays.ArrayData;
46 import jdk.nashorn.internal.runtime.ConsString;
47 import jdk.nashorn.internal.runtime.Context;
48 import jdk.nashorn.internal.runtime.GlobalObject;
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 ScriptObject 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 ScriptObject 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 ScriptObject 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 {
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 ScriptObject 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;
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 ScriptObject ? new ScriptObjectMirror((ScriptObject)obj, (ScriptObject)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
691 * Unwrap an array of script object mirrors if needed.
692 *
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 ScriptObject global) {
714 assert sobj != null : "ScriptObjectMirror on null!";
715 assert global instanceof GlobalObject : "global is not a GlobalObject";
716
717 this.sobj = sobj;
718 this.global = global;
719 this.strict = ((GlobalObject)global).isStrictContext();
720 }
721
722 // accessors for script engine
723 ScriptObject getScriptObject() {
724 return sobj;
725 }
726
727 ScriptObject 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 ScriptObject 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
|
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 {
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;
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
691 * Unwrap an array of script object mirrors if needed.
692 *
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.ScriptObject
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
|