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

Print this page




  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.Context;

  45 import jdk.nashorn.internal.runtime.ScriptFunction;
  46 import jdk.nashorn.internal.runtime.ScriptObject;
  47 import jdk.nashorn.internal.runtime.ScriptRuntime;
  48 
  49 /**
  50  * Mirror object that wraps a given ScriptObject instance. User can
  51  * access ScriptObject via the javax.script.Bindings interface or
  52  * netscape.javascript.JSObject interface.
  53  */
  54 public final class ScriptObjectMirror extends JSObject implements Bindings {
  55     private static AccessControlContext getContextAccCtxt() {
  56         final Permissions perms = new Permissions();
  57         perms.add(new RuntimePermission(Context.NASHORN_GET_CONTEXT));
  58         return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
  59     }
  60 
  61     private static final AccessControlContext GET_CONTEXT_ACC_CTXT = getContextAccCtxt();
  62 
  63     private final ScriptObject sobj;
  64     private final ScriptObject global;

  65 
  66     @Override
  67     public boolean equals(final Object other) {
  68         if (other instanceof ScriptObjectMirror) {
  69             return sobj.equals(((ScriptObjectMirror)other).sobj);
  70         }
  71 
  72         return false;
  73     }
  74 
  75     @Override
  76     public int hashCode() {
  77         return sobj.hashCode();
  78     }
  79 
  80     @Override
  81     public String toString() {
  82         return inGlobal(new Callable<String>() {
  83             @Override
  84             public String call() {
  85                 return ScriptRuntime.safeToString(sobj);
  86             }
  87         });
  88     }
  89 
  90     // JSObject methods
  91     @Override
  92     public Object call(final String functionName, final Object... args) {
  93         final ScriptObject oldGlobal = Context.getGlobal();
  94         final boolean globalChanged = (oldGlobal != global);
  95 
  96         try {
  97             if (globalChanged) {
  98                 Context.setGlobal(global);
  99             }
 100 
 101             final Object val = functionName == null? sobj : sobj.get(functionName);
 102             if (val instanceof ScriptFunction) {
 103                 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
 104                 return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
 105             } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
 106                 return ((ScriptObjectMirror)val).call(null, args);
 107             }
 108 
 109             throw new NoSuchMethodException("No such function " + ((functionName != null)? functionName : ""));
 110         } catch (final RuntimeException | Error e) {
 111             throw e;
 112         } catch (final Throwable t) {
 113             throw new RuntimeException(t);
 114         } finally {
 115             if (globalChanged) {
 116                 Context.setGlobal(oldGlobal);
 117             }
 118         }
 119     }
 120 
 121     @Override
 122     public Object newObject(final String functionName, final Object... args) {
 123         final ScriptObject oldGlobal = Context.getGlobal();
 124         final boolean globalChanged = (oldGlobal != global);
 125 
 126         try {
 127             if (globalChanged) {
 128                 Context.setGlobal(global);
 129             }
 130 
 131             final Object val = functionName == null? sobj : sobj.get(functionName);
 132             if (val instanceof ScriptFunction) {
 133                 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
 134                 return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global);
 135             } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
 136                 return ((ScriptObjectMirror)val).newObject(null, args);
 137             }
 138 
 139             throw new RuntimeException("not a constructor " + ((functionName != null)? functionName : ""));
 140         } catch (final RuntimeException | Error e) {
 141             throw e;
 142         } catch (final Throwable t) {
 143             throw new RuntimeException(t);
 144         } finally {
 145             if (globalChanged) {
 146                 Context.setGlobal(oldGlobal);
 147             }
 148         }
 149     }
 150 
 151     @Override
 152     public Object eval(final String s) {
 153         return inGlobal(new Callable<Object>() {
 154             @Override


 180             @Override public Object call() {
 181                 return wrap(sobj.get(index), global);
 182             }
 183         });
 184     }
 185 
 186     @Override
 187     public void removeMember(final String name) {
 188         remove(name);
 189     }
 190 
 191     @Override
 192     public void setMember(final String name, final Object value) {
 193         put(name, value);
 194     }
 195 
 196     @Override
 197     public void setSlot(final int index, final Object value) {
 198         inGlobal(new Callable<Void>() {
 199             @Override public Void call() {
 200                 sobj.set(index, unwrap(value, global), global.isStrictContext());
 201                 return null;
 202             }
 203         });
 204     }
 205 
 206     // javax.script.Bindings methods
 207 
 208     @Override
 209     public void clear() {
 210         inGlobal(new Callable<Object>() {
 211             @Override public Object call() {
 212                 sobj.clear();
 213                 return null;
 214             }
 215         });
 216     }
 217 
 218     @Override
 219     public boolean containsKey(final Object key) {
 220         return inGlobal(new Callable<Boolean>() {
 221             @Override public Boolean call() {
 222                 return sobj.containsKey(unwrap(key, global));
 223             }
 224         });
 225     }
 226 
 227     @Override
 228     public boolean containsValue(final Object value) {
 229         return inGlobal(new Callable<Boolean>() {
 230             @Override public Boolean call() {
 231                 return sobj.containsValue(unwrap(value, global));
 232             }


 275             @Override public Set<String> call() {
 276                 final Iterator<String> iter   = sobj.propertyIterator();
 277                 final Set<String>      keySet = new LinkedHashSet<>();
 278 
 279                 while (iter.hasNext()) {
 280                     keySet.add(iter.next());
 281                 }
 282 
 283                 return Collections.unmodifiableSet(keySet);
 284             }
 285         });
 286     }
 287 
 288     @Override
 289     public Object put(final String key, final Object value) {
 290         final ScriptObject oldGlobal = Context.getGlobal();
 291         final boolean globalChanged = (oldGlobal != global);
 292         return inGlobal(new Callable<Object>() {
 293             @Override public Object call() {
 294                 final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
 295                 return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global)), global));
 296             }
 297         });
 298     }
 299 
 300     @Override
 301     public void putAll(final Map<? extends String, ? extends Object> map) {
 302         final ScriptObject oldGlobal = Context.getGlobal();
 303         final boolean globalChanged = (oldGlobal != global);
 304         inGlobal(new Callable<Object>() {
 305             @Override public Object call() {
 306                 final boolean strict = global.isStrictContext();
 307                 for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
 308                     final Object value = entry.getValue();
 309                     final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
 310                     sobj.set(entry.getKey(), unwrap(modValue, global), strict);
 311                 }
 312                 return null;
 313             }
 314         });
 315     }
 316 
 317     @Override
 318     public Object remove(final Object key) {
 319         return inGlobal(new Callable<Object>() {
 320             @Override public Object call() {
 321                 return wrap(sobj.remove(unwrap(key, global)), global);
 322             }
 323         });
 324     }
 325 
 326     /**
 327      * Delete a property from this object.
 328      *
 329      * @param key the property to be deleted
 330      *
 331      * @return if the delete was successful or not
 332      */
 333     public boolean delete(final Object key) {
 334         return inGlobal(new Callable<Boolean>() {
 335             @Override public Boolean call() {
 336                 return sobj.delete(unwrap(key, global));
 337             }
 338         });
 339     }
 340 
 341     @Override
 342     public int size() {
 343         return inGlobal(new Callable<Integer>() {
 344             @Override public Integer call() {
 345                 return sobj.size();
 346             }
 347         });
 348     }
 349 
 350     @Override
 351     public Collection<Object> values() {
 352         return inGlobal(new Callable<Collection<Object>>() {
 353             @Override public Collection<Object> call() {
 354                 final List<Object>     values = new ArrayList<>(size());
 355                 final Iterator<Object> iter   = sobj.valueIterator();
 356 


 620      * @return unwrapped array
 621      */
 622     public static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) {
 623         if (args == null || args.length == 0) {
 624             return args;
 625         }
 626 
 627         final Object[] newArgs = new Object[args.length];
 628         int index = 0;
 629         for (final Object obj : args) {
 630             newArgs[index] = unwrap(obj, homeGlobal);
 631             index++;
 632         }
 633         return newArgs;
 634     }
 635 
 636     // package-privates below this.
 637 
 638     ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
 639         assert sobj != null : "ScriptObjectMirror on null!";
 640         assert global != null : "null global for ScriptObjectMirror!";
 641 
 642         this.sobj = sobj;
 643         this.global = global;

 644     }
 645 
 646     // accessors for script engine
 647     ScriptObject getScriptObject() {
 648         return sobj;
 649     }
 650 
 651     ScriptObject getHomeGlobal() {
 652         return global;
 653     }
 654 
 655     static Object translateUndefined(Object obj) {
 656         return (obj == ScriptRuntime.UNDEFINED)? null : obj;
 657     }
 658 
 659     // internals only below this.
 660     private <V> V inGlobal(final Callable<V> callable) {
 661         final ScriptObject oldGlobal = Context.getGlobal();
 662         final boolean globalChanged = (oldGlobal != global);
 663         if (globalChanged) {


  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.Context;
  45 import jdk.nashorn.internal.runtime.GlobalObject;
  46 import jdk.nashorn.internal.runtime.ScriptFunction;
  47 import jdk.nashorn.internal.runtime.ScriptObject;
  48 import jdk.nashorn.internal.runtime.ScriptRuntime;
  49 
  50 /**
  51  * Mirror object that wraps a given ScriptObject instance. User can
  52  * access ScriptObject via the javax.script.Bindings interface or
  53  * netscape.javascript.JSObject interface.
  54  */
  55 public final class ScriptObjectMirror extends JSObject 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     @Override
  94     public Object call(final String functionName, final Object... args) {
  95         final ScriptObject oldGlobal = Context.getGlobal();
  96         final boolean globalChanged = (oldGlobal != global);
  97 
  98         try {
  99             if (globalChanged) {
 100                 Context.setGlobal(global);
 101             }
 102 
 103             final Object val = functionName == null? sobj : sobj.get(functionName);
 104             if (val instanceof ScriptFunction) {
 105                 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
 106                 return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
 107             } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
 108                 return ((ScriptObjectMirror)val).call(null, args);
 109             }
 110 
 111             throw new NoSuchMethodException("No such function " + ((functionName != null)? functionName : ""));
 112         } catch (final RuntimeException | Error e) {
 113             throw e;
 114         } catch (final Throwable t) {
 115             throw new RuntimeException(t);
 116         } finally {
 117             if (globalChanged) {
 118                 Context.setGlobal(oldGlobal);
 119             }
 120         }
 121     }
 122 
 123     @Override
 124     public Object newObject(final String functionName, final Object... args) {
 125         final ScriptObject oldGlobal = Context.getGlobal();
 126         final boolean globalChanged = (oldGlobal != global);
 127 
 128         try {
 129             if (globalChanged) {
 130                 Context.setGlobal(global);
 131             }
 132 
 133             final Object val = functionName == null? sobj : sobj.get(functionName);
 134             if (val instanceof ScriptFunction) {
 135                 final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
 136                 return wrap(ScriptRuntime.construct((ScriptFunction)val, unwrapArray(modArgs, global)), global);
 137             } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) {
 138                 return ((ScriptObjectMirror)val).newObject(null, args);
 139             }
 140 
 141             throw new RuntimeException("not a constructor " + ((functionName != null)? functionName : ""));
 142         } catch (final RuntimeException | Error e) {
 143             throw e;
 144         } catch (final Throwable t) {
 145             throw new RuntimeException(t);
 146         } finally {
 147             if (globalChanged) {
 148                 Context.setGlobal(oldGlobal);
 149             }
 150         }
 151     }
 152 
 153     @Override
 154     public Object eval(final String s) {
 155         return inGlobal(new Callable<Object>() {
 156             @Override


 182             @Override public Object call() {
 183                 return wrap(sobj.get(index), global);
 184             }
 185         });
 186     }
 187 
 188     @Override
 189     public void removeMember(final String name) {
 190         remove(name);
 191     }
 192 
 193     @Override
 194     public void setMember(final String name, final Object value) {
 195         put(name, value);
 196     }
 197 
 198     @Override
 199     public void setSlot(final int index, final Object value) {
 200         inGlobal(new Callable<Void>() {
 201             @Override public Void call() {
 202                 sobj.set(index, unwrap(value, global), strict);
 203                 return null;
 204             }
 205         });
 206     }
 207 
 208     // javax.script.Bindings methods
 209 
 210     @Override
 211     public void clear() {
 212         inGlobal(new Callable<Object>() {
 213             @Override public Object call() {
 214                 sobj.clear(strict);
 215                 return null;
 216             }
 217         });
 218     }
 219 
 220     @Override
 221     public boolean containsKey(final Object key) {
 222         return inGlobal(new Callable<Boolean>() {
 223             @Override public Boolean call() {
 224                 return sobj.containsKey(unwrap(key, global));
 225             }
 226         });
 227     }
 228 
 229     @Override
 230     public boolean containsValue(final Object value) {
 231         return inGlobal(new Callable<Boolean>() {
 232             @Override public Boolean call() {
 233                 return sobj.containsValue(unwrap(value, global));
 234             }


 277             @Override public Set<String> call() {
 278                 final Iterator<String> iter   = sobj.propertyIterator();
 279                 final Set<String>      keySet = new LinkedHashSet<>();
 280 
 281                 while (iter.hasNext()) {
 282                     keySet.add(iter.next());
 283                 }
 284 
 285                 return Collections.unmodifiableSet(keySet);
 286             }
 287         });
 288     }
 289 
 290     @Override
 291     public Object put(final String key, final Object value) {
 292         final ScriptObject oldGlobal = Context.getGlobal();
 293         final boolean globalChanged = (oldGlobal != global);
 294         return inGlobal(new Callable<Object>() {
 295             @Override public Object call() {
 296                 final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
 297                 return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global), strict), global));
 298             }
 299         });
 300     }
 301 
 302     @Override
 303     public void putAll(final Map<? extends String, ? extends Object> map) {
 304         final ScriptObject oldGlobal = Context.getGlobal();
 305         final boolean globalChanged = (oldGlobal != global);
 306         inGlobal(new Callable<Object>() {
 307             @Override public Object call() {

 308                 for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
 309                     final Object value = entry.getValue();
 310                     final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
 311                     sobj.set(entry.getKey(), unwrap(modValue, global), strict);
 312                 }
 313                 return null;
 314             }
 315         });
 316     }
 317 
 318     @Override
 319     public Object remove(final Object key) {
 320         return inGlobal(new Callable<Object>() {
 321             @Override public Object call() {
 322                 return wrap(sobj.remove(unwrap(key, global), strict), global);
 323             }
 324         });
 325     }
 326 
 327     /**
 328      * Delete a property from this object.
 329      *
 330      * @param key the property to be deleted
 331      *
 332      * @return if the delete was successful or not
 333      */
 334     public boolean delete(final Object key) {
 335         return inGlobal(new Callable<Boolean>() {
 336             @Override public Boolean call() {
 337                 return sobj.delete(unwrap(key, global), strict);
 338             }
 339         });
 340     }
 341 
 342     @Override
 343     public int size() {
 344         return inGlobal(new Callable<Integer>() {
 345             @Override public Integer call() {
 346                 return sobj.size();
 347             }
 348         });
 349     }
 350 
 351     @Override
 352     public Collection<Object> values() {
 353         return inGlobal(new Callable<Collection<Object>>() {
 354             @Override public Collection<Object> call() {
 355                 final List<Object>     values = new ArrayList<>(size());
 356                 final Iterator<Object> iter   = sobj.valueIterator();
 357 


 621      * @return unwrapped array
 622      */
 623     public static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) {
 624         if (args == null || args.length == 0) {
 625             return args;
 626         }
 627 
 628         final Object[] newArgs = new Object[args.length];
 629         int index = 0;
 630         for (final Object obj : args) {
 631             newArgs[index] = unwrap(obj, homeGlobal);
 632             index++;
 633         }
 634         return newArgs;
 635     }
 636 
 637     // package-privates below this.
 638 
 639     ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
 640         assert sobj != null : "ScriptObjectMirror on null!";
 641         assert global instanceof GlobalObject : "global is not a GlobalObject";
 642 
 643         this.sobj = sobj;
 644         this.global = global;
 645         this.strict = ((GlobalObject)global).isStrictContext();
 646     }
 647 
 648     // accessors for script engine
 649     ScriptObject getScriptObject() {
 650         return sobj;
 651     }
 652 
 653     ScriptObject getHomeGlobal() {
 654         return global;
 655     }
 656 
 657     static Object translateUndefined(Object obj) {
 658         return (obj == ScriptRuntime.UNDEFINED)? null : obj;
 659     }
 660 
 661     // internals only below this.
 662     private <V> V inGlobal(final Callable<V> callable) {
 663         final ScriptObject oldGlobal = Context.getGlobal();
 664         final boolean globalChanged = (oldGlobal != global);
 665         if (globalChanged) {