1 /*
   2  * Copyright (c) 2005, 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  */
  25 
  26 package javax.script;
  27 
  28 import java.util.*;
  29 import java.io.*;
  30 
  31 /**
  32  * Simple implementation of ScriptContext.
  33  *
  34  * @author Mike Grogan
  35  * @since 1.6
  36  */
  37 public class SimpleScriptContext  implements ScriptContext {
  38 
  39     /**
  40      * This is the writer to be used to output from scripts.
  41      * By default, a <code>PrintWriter</code> based on <code>System.out</code>
  42      * is used. Accessor methods getWriter, setWriter are used to manage
  43      * this field.
  44      * @see java.lang.System#out
  45      * @see java.io.PrintWriter
  46      */
  47     protected Writer writer;
  48 
  49     /**
  50      * This is the writer to be used to output errors from scripts.
  51      * By default, a <code>PrintWriter</code> based on <code>System.err</code> is
  52      * used. Accessor methods getErrorWriter, setErrorWriter are used to manage
  53      * this field.
  54      * @see java.lang.System#err
  55      * @see java.io.PrintWriter
  56      */
  57     protected Writer errorWriter;
  58 
  59     /**
  60      * This is the reader to be used for input from scripts.
  61      * By default, a <code>InputStreamReader</code> based on <code>System.in</code>
  62      * is used and default charset is used by this reader. Accessor methods
  63      * getReader, setReader are used to manage this field.
  64      * @see java.lang.System#in
  65      * @see java.io.InputStreamReader
  66      */
  67     protected Reader reader;
  68 
  69 
  70     /**
  71      * This is the engine scope bindings.
  72      * By default, a <code>SimpleBindings</code> is used. Accessor
  73      * methods setBindings, getBindings are used to manage this field.
  74      * @see SimpleBindings
  75      */
  76     protected Bindings engineScope;
  77 
  78     /**
  79      * This is the global scope bindings.
  80      * By default, a null value (which means no global scope) is used. Accessor
  81      * methods setBindings, getBindings are used to manage this field.
  82      */
  83     protected Bindings globalScope;
  84 
  85     /**
  86      * Create a {@code SimpleScriptContext}.
  87      */
  88     public SimpleScriptContext() {
  89         engineScope = new SimpleBindings();
  90         globalScope = null;
  91         reader = new InputStreamReader(System.in);
  92         writer = new PrintWriter(System.out , true);
  93         errorWriter = new PrintWriter(System.err, true);
  94     }
  95 
  96     /**
  97      * Sets a <code>Bindings</code> of attributes for the given scope.  If the value
  98      * of scope is <code>ENGINE_SCOPE</code> the given <code>Bindings</code> replaces the
  99      * <code>engineScope</code> field.  If the value
 100      * of scope is <code>GLOBAL_SCOPE</code> the given <code>Bindings</code> replaces the
 101      * <code>globalScope</code> field.
 102      *
 103      * @param bindings The <code>Bindings</code> of attributes to set.
 104      * @param scope The value of the scope in which the attributes are set.
 105      *
 106      * @throws IllegalArgumentException if scope is invalid.
 107      * @throws NullPointerException if the value of scope is <code>ENGINE_SCOPE</code> and
 108      * the specified <code>Bindings</code> is null.
 109      */
 110     public void setBindings(Bindings bindings, int scope) {
 111 
 112         switch (scope) {
 113 
 114             case ENGINE_SCOPE:
 115                 if (bindings == null) {
 116                     throw new NullPointerException("Engine scope cannot be null.");
 117                 }
 118                 engineScope = bindings;
 119                 break;
 120             case GLOBAL_SCOPE:
 121                 globalScope = bindings;
 122                 break;
 123             default:
 124                 throw new IllegalArgumentException("Invalid scope value.");
 125         }
 126     }
 127 
 128 
 129     /**
 130      * Retrieves the value of the attribute with the given name in
 131      * the scope occurring earliest in the search order.  The order
 132      * is determined by the numeric value of the scope parameter (lowest
 133      * scope values first.)
 134      *
 135      * @param name The name of the attribute to retrieve.
 136      * @return The value of the attribute in the lowest scope for
 137      * which an attribute with the given name is defined.  Returns
 138      * null if no attribute with the name exists in any scope.
 139      * @throws NullPointerException if the name is null.
 140      * @throws IllegalArgumentException if the name is empty.
 141      */
 142     public Object getAttribute(String name) {
 143         checkName(name);
 144         if (engineScope.containsKey(name)) {
 145             return getAttribute(name, ENGINE_SCOPE);
 146         } else if (globalScope != null && globalScope.containsKey(name)) {
 147             return getAttribute(name, GLOBAL_SCOPE);
 148         }
 149 
 150         return null;
 151     }
 152 
 153     /**
 154      * Gets the value of an attribute in a given scope.
 155      *
 156      * @param name The name of the attribute to retrieve.
 157      * @param scope The scope in which to retrieve the attribute.
 158      * @return The value of the attribute. Returns <code>null</code> is the name
 159      * does not exist in the given scope.
 160      *
 161      * @throws IllegalArgumentException
 162      *         if the name is empty or if the value of scope is invalid.
 163      * @throws NullPointerException if the name is null.
 164      */
 165     public Object getAttribute(String name, int scope) {
 166         checkName(name);
 167         switch (scope) {
 168 
 169             case ENGINE_SCOPE:
 170                 return engineScope.get(name);
 171 
 172             case GLOBAL_SCOPE:
 173                 if (globalScope != null) {
 174                     return globalScope.get(name);
 175                 }
 176                 return null;
 177 
 178             default:
 179                 throw new IllegalArgumentException("Illegal scope value.");
 180         }
 181     }
 182 
 183     /**
 184      * Remove an attribute in a given scope.
 185      *
 186      * @param name The name of the attribute to remove
 187      * @param scope The scope in which to remove the attribute
 188      *
 189      * @return The removed value.
 190      * @throws IllegalArgumentException
 191      *         if the name is empty or if the scope is invalid.
 192      * @throws NullPointerException if the name is null.
 193      */
 194     public Object removeAttribute(String name, int scope) {
 195         checkName(name);
 196         switch (scope) {
 197 
 198             case ENGINE_SCOPE:
 199                 if (getBindings(ENGINE_SCOPE) != null) {
 200                     return getBindings(ENGINE_SCOPE).remove(name);
 201                 }
 202                 return null;
 203 
 204             case GLOBAL_SCOPE:
 205                 if (getBindings(GLOBAL_SCOPE) != null) {
 206                     return getBindings(GLOBAL_SCOPE).remove(name);
 207                 }
 208                 return null;
 209 
 210             default:
 211                 throw new IllegalArgumentException("Illegal scope value.");
 212         }
 213     }
 214 
 215     /**
 216      * Sets the value of an attribute in a given scope.
 217      *
 218      * @param name The name of the attribute to set
 219      * @param value The value of the attribute
 220      * @param scope The scope in which to set the attribute
 221      *
 222      * @throws IllegalArgumentException
 223      *         if the name is empty or if the scope is invalid.
 224      * @throws NullPointerException if the name is null.
 225      */
 226     public void setAttribute(String name, Object value, int scope) {
 227         checkName(name);
 228         switch (scope) {
 229 
 230             case ENGINE_SCOPE:
 231                 engineScope.put(name, value);
 232                 return;
 233 
 234             case GLOBAL_SCOPE:
 235                 if (globalScope != null) {
 236                     globalScope.put(name, value);
 237                 }
 238                 return;
 239 
 240             default:
 241                 throw new IllegalArgumentException("Illegal scope value.");
 242         }
 243     }
 244 
 245     /** {@inheritDoc} */
 246     public Writer getWriter() {
 247         return writer;
 248     }
 249 
 250     /** {@inheritDoc} */
 251     public Reader getReader() {
 252         return reader;
 253     }
 254 
 255     /** {@inheritDoc} */
 256     public void setReader(Reader reader) {
 257         this.reader = reader;
 258     }
 259 
 260     /** {@inheritDoc} */
 261     public void setWriter(Writer writer) {
 262         this.writer = writer;
 263     }
 264 
 265     /** {@inheritDoc} */
 266     public Writer getErrorWriter() {
 267         return errorWriter;
 268     }
 269 
 270     /** {@inheritDoc} */
 271     public void setErrorWriter(Writer writer) {
 272         this.errorWriter = writer;
 273     }
 274 
 275     /**
 276      * Get the lowest scope in which an attribute is defined.
 277      * @param name Name of the attribute
 278      * .
 279      * @return The lowest scope.  Returns -1 if no attribute with the given
 280      * name is defined in any scope.
 281      * @throws NullPointerException if name is null.
 282      * @throws IllegalArgumentException if name is empty.
 283      */
 284     public int getAttributesScope(String name) {
 285         checkName(name);
 286         if (engineScope.containsKey(name)) {
 287             return ENGINE_SCOPE;
 288         } else if (globalScope != null && globalScope.containsKey(name)) {
 289             return GLOBAL_SCOPE;
 290         } else {
 291             return -1;
 292         }
 293     }
 294 
 295     /**
 296      * Returns the value of the <code>engineScope</code> field if specified scope is
 297      * <code>ENGINE_SCOPE</code>.  Returns the value of the <code>globalScope</code> field if the specified scope is
 298      * <code>GLOBAL_SCOPE</code>.
 299      *
 300      * @param scope The specified scope
 301      * @return The value of either the  <code>engineScope</code> or <code>globalScope</code> field.
 302      * @throws IllegalArgumentException if the value of scope is invalid.
 303      */
 304     public Bindings getBindings(int scope) {
 305         if (scope == ENGINE_SCOPE) {
 306             return engineScope;
 307         } else if (scope == GLOBAL_SCOPE) {
 308             return globalScope;
 309         } else {
 310             throw new IllegalArgumentException("Illegal scope value.");
 311         }
 312     }
 313 
 314     /** {@inheritDoc} */
 315     public List<Integer> getScopes() {
 316         return scopes;
 317     }
 318 
 319     private void checkName(String name) {
 320         Objects.requireNonNull(name);
 321         if (name.isEmpty()) {
 322             throw new IllegalArgumentException("name cannot be empty");
 323         }
 324     }
 325 
 326     private static List<Integer> scopes;
 327     static {
 328         scopes = new ArrayList<Integer>(2);
 329         scopes.add(ENGINE_SCOPE);
 330         scopes.add(GLOBAL_SCOPE);
 331         scopes = Collections.unmodifiableList(scopes);
 332     }
 333 }