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

Wed, 16 Jan 2013 17:58:51 +0530

author
sundar
date
Wed, 16 Jan 2013 17:58:51 +0530
changeset 33
80447df16322
parent 7
5a1b0714df0e
child 38
c887baec012a
permissions
-rw-r--r--

8006412: Improve toString method of ScriptObjectMirror class
Reviewed-by: jlaskey, lagergren

     1 /*
     2  * Copyright (c) 2010, 2013, 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  */
    26 package jdk.nashorn.api.scripting;
    28 import java.util.AbstractMap;
    29 import java.util.ArrayList;
    30 import java.util.Collection;
    31 import java.util.Collections;
    32 import java.util.HashSet;
    33 import java.util.Iterator;
    34 import java.util.List;
    35 import java.util.Map;
    36 import java.util.Set;
    37 import java.util.concurrent.Callable;
    38 import jdk.nashorn.internal.runtime.Context;
    39 import jdk.nashorn.internal.runtime.ScriptFunction;
    40 import jdk.nashorn.internal.runtime.ScriptObject;
    41 import jdk.nashorn.internal.runtime.ScriptRuntime;
    42 import netscape.javascript.JSObject;
    44 /**
    45  * Mirror object that wraps a given ScriptObject instance. User can
    46  * access ScriptObject via the java.util.Map interface.
    47  */
    48 final class ScriptObjectMirror extends JSObject implements Map<Object, Object> {
    49     private final ScriptObject sobj;
    50     private final ScriptObject global;
    52     ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
    53         this.sobj = sobj;
    54         this.global = global;
    55     }
    57     @Override
    58     public boolean equals(final Object other) {
    59         if (other instanceof ScriptObjectMirror) {
    60             return sobj.equals(((ScriptObjectMirror)other).sobj);
    61         }
    63         return false;
    64     }
    66     @Override
    67     public int hashCode() {
    68         return sobj.hashCode();
    69     }
    71     @Override
    72     public String toString() {
    73         return inGlobal(new Callable<String>() {
    74             @Override
    75             public String call() {
    76                 return ScriptRuntime.safeToString(sobj);
    77             }
    78         });
    79     }
    81     private <V> V inGlobal(final Callable<V> callable) {
    82         final ScriptObject oldGlobal = Context.getGlobal();
    83         final boolean globalChanged = (oldGlobal != global);
    84         if (globalChanged) {
    85             NashornScriptEngine.setNashornGlobal(global);
    86         }
    87         try {
    88             return callable.call();
    89         } catch (final RuntimeException e) {
    90             throw e;
    91         } catch (final Exception e) {
    92             throw new AssertionError("Cannot happen", e);
    93         } finally {
    94             if (globalChanged) {
    95                 NashornScriptEngine.setNashornGlobal(oldGlobal);
    96             }
    97         }
    98     }
   100     // JSObject methods
   101     @Override
   102     public Object call(final String methodName, final Object args[]) {
   103         final Object val = sobj.get(methodName);
   104         final ScriptObject oldGlobal = Context.getGlobal();
   105         final boolean globalChanged = (oldGlobal != global);
   107         if (val instanceof ScriptFunction) {
   108             final Object[] modifiedArgs = unwrapArray(args, global);
   109             if (modifiedArgs != null) {
   110                 for (int i = 0; i < modifiedArgs.length; i++) {
   111                     final Object arg = modifiedArgs[i];
   112                     if (arg instanceof ScriptObject) {
   113                         modifiedArgs[i] = wrap(arg, oldGlobal);
   114                     }
   115                 }
   116             }
   118             try {
   119                 if (globalChanged) {
   120                     NashornScriptEngine.setNashornGlobal(global);
   121                 }
   122                 return wrap(((ScriptFunction)val).invoke(sobj, modifiedArgs), global);
   123             } catch (final RuntimeException | Error e) {
   124                 throw e;
   125             } catch (final Throwable t) {
   126                 throw new RuntimeException(t);
   127             } finally {
   128                 if (globalChanged) {
   129                     NashornScriptEngine.setNashornGlobal(oldGlobal);
   130                 }
   131             }
   132        }
   134        throw new RuntimeException("No such method: " + methodName);
   135     }
   137     @Override
   138     public Object eval(final String s) {
   139         return inGlobal(new Callable<Object>() {
   140             @Override
   141             public Object call() {
   142                 return wrap(global.getContext().eval(global, s, null, null, false), global);
   143             }
   144         });
   145     }
   147     @Override
   148     public Object getMember(final String name) {
   149         return get(name);
   150     }
   152     @Override
   153     public Object getSlot(final int index) {
   154         return get(Integer.valueOf(index));
   155     }
   157     @Override
   158     public void removeMember(final String name) {
   159         remove(name);
   160     }
   162     @Override
   163     public void setMember(final String name, final Object value) {
   164         put(name, wrap(value, Context.getGlobal()));
   165     }
   167     @Override
   168     public void setSlot(final int index, final Object value) {
   169         put(Integer.valueOf(index), wrap(value, Context.getGlobal()));
   170     }
   172     @Override
   173     public void clear() {
   174         inGlobal(new Callable<Object>() {
   175             @Override public Object call() {
   176                 sobj.clear();
   177                 return null;
   178             }});
   179     }
   181     @Override
   182     public boolean containsKey(final Object key) {
   183         return inGlobal(new Callable<Boolean>() {
   184             @Override public Boolean call() {
   185                 return sobj.containsKey(unwrap(key, global));
   186             }});
   187     }
   189     @Override
   190     public boolean containsValue(final Object value) {
   191         return inGlobal(new Callable<Boolean>() {
   192             @Override public Boolean call() {
   193                 return sobj.containsValue(unwrap(value, global));
   194             }});
   195     }
   197     @Override
   198     public Set<Map.Entry<Object, Object>> entrySet() {
   199         return inGlobal(new Callable<Set<Map.Entry<Object, Object>>>() {
   200             @Override public Set<Map.Entry<Object, Object>> call() {
   201                 final Iterator<String>               iter    = sobj.propertyIterator();
   202                 final Set<Map.Entry<Object, Object>> entries = new HashSet<>();
   204                 while (iter.hasNext()) {
   205                     final Object key   = wrap(iter.next(), global);
   206                     final Object value = wrap(sobj.get(key), global);
   207                     entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value));
   208                 }
   210                 return Collections.unmodifiableSet(entries);
   211             }
   212         });
   213     }
   215     @Override
   216     public Object get(final Object key) {
   217         return inGlobal(new Callable<Object>() { @Override public Object call() {
   218             return wrap(sobj.get(key), global);
   219         }});
   220     }
   222     @Override
   223     public boolean isEmpty() {
   224         return inGlobal(new Callable<Boolean>() { @Override public Boolean call() {
   225             return sobj.isEmpty();
   226         }});
   227     }
   229     @Override
   230     public Set<Object> keySet() {
   231         return inGlobal(new Callable<Set<Object>>() { @Override public Set<Object> call() {
   232             final Iterator<String> iter   = sobj.propertyIterator();
   233             final Set<Object>      keySet = new HashSet<>();
   235             while (iter.hasNext()) {
   236                 keySet.add(wrap(iter.next(), global));
   237             }
   239             return Collections.unmodifiableSet(keySet);
   240         }});
   241     }
   243     @Override
   244     public Object put(final Object key, final Object value) {
   245         return inGlobal(new Callable<Object>() {
   246             @Override public Object call() {
   247                 return sobj.put(unwrap(key, global), unwrap(value, global));
   248         }});
   249     }
   251     @Override
   252     public void putAll(final Map<?, ?> map) {
   253         final boolean strict = sobj.getContext()._strict;
   254         inGlobal(new Callable<Object>() { @Override public Object call() {
   255             for (final Map.Entry<?, ?> entry : map.entrySet()) {
   256                 sobj.set(unwrap(entry.getKey(), global), unwrap(entry.getValue(), global), strict);
   257             }
   258             return null;
   259         }});
   260     }
   262     @Override
   263     public Object remove(final Object key) {
   264         return inGlobal(new Callable<Object>() {
   265             @Override public Object call() {
   266                 return wrap(sobj.remove(unwrap(key, global)), global);
   267             }
   268         });
   269     }
   271     @Override
   272     public int size() {
   273         return inGlobal(new Callable<Integer>() {
   274             @Override public Integer call() {
   275                 return sobj.size();
   276             }
   277         });
   278     }
   280     @Override
   281     public Collection<Object> values() {
   282         return inGlobal(new Callable<Collection<Object>>() { @Override public Collection<Object> call() {
   283             final List<Object>     values = new ArrayList<>(size());
   284             final Iterator<Object> iter   = sobj.valueIterator();
   286             while (iter.hasNext()) {
   287                 values.add(wrap(iter.next(), global));
   288             }
   290             return Collections.unmodifiableList(values);
   291         }});
   292     }
   294     static Object wrap(final Object obj, final ScriptObject homeGlobal) {
   295         return (obj instanceof ScriptObject) ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj;
   296     }
   298     static Object unwrap(final Object obj, final ScriptObject homeGlobal) {
   299         if (obj instanceof ScriptObjectMirror) {
   300             final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
   301             return (mirror.global == homeGlobal)? mirror.sobj : obj;
   302         }
   304         return obj;
   305     }
   307     static Object[] wrapArray(final Object[] args, final ScriptObject homeGlobal) {
   308         if (args == null || args.length == 0) {
   309             return args;
   310         }
   312         final Object[] newArgs = new Object[args.length];
   313         int index = 0;
   314         for (final Object obj : args) {
   315             newArgs[index] = wrap(obj, homeGlobal);
   316             index++;
   317         }
   318         return newArgs;
   319     }
   321     static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) {
   322         if (args == null || args.length == 0) {
   323             return args;
   324         }
   326         final Object[] newArgs = new Object[args.length];
   327         int index = 0;
   328         for (final Object obj : args) {
   329             newArgs[index] = unwrap(obj, homeGlobal);
   330             index++;
   331         }
   332         return newArgs;
   333     }
   334 }

mercurial