src/jdk/nashorn/api/scripting/ScriptObjectMirror.java

Print this page




  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