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 */ SimpleScriptContext()88 public SimpleScriptContext() { 89 this(new InputStreamReader(System.in), 90 new PrintWriter(System.out , true), 91 new PrintWriter(System.err, true)); 92 engineScope = new SimpleBindings(); 93 globalScope = null; 94 } 95 96 /** 97 * Package-private constructor to avoid needless creation of reader and writers. 98 * It is the caller's responsability to initialize the engine scope. 99 * 100 * @param reader the reader 101 * @param writer the writer 102 * @param errorWriter the error writer 103 */ SimpleScriptContext(Reader reader, Writer writer, Writer errorWriter)104 SimpleScriptContext(Reader reader, Writer writer, Writer errorWriter) { 105 this.reader = reader; 106 this.writer = writer; 107 this.errorWriter = errorWriter; 108 } 109 110 /** 111 * Sets a <code>Bindings</code> of attributes for the given scope. If the value 112 * of scope is <code>ENGINE_SCOPE</code> the given <code>Bindings</code> replaces the 113 * <code>engineScope</code> field. If the value 114 * of scope is <code>GLOBAL_SCOPE</code> the given <code>Bindings</code> replaces the 115 * <code>globalScope</code> field. 116 * 117 * @param bindings The <code>Bindings</code> of attributes to set. 118 * @param scope The value of the scope in which the attributes are set. 119 * 120 * @throws IllegalArgumentException if scope is invalid. 121 * @throws NullPointerException if the value of scope is <code>ENGINE_SCOPE</code> and 122 * the specified <code>Bindings</code> is null. 123 */ setBindings(Bindings bindings, int scope)124 public void setBindings(Bindings bindings, int scope) { 125 126 switch (scope) { 127 128 case ENGINE_SCOPE: 129 if (bindings == null) { 130 throw new NullPointerException("Engine scope cannot be null."); 131 } 132 engineScope = bindings; 133 break; 134 case GLOBAL_SCOPE: 135 globalScope = bindings; 136 break; 137 default: 138 throw new IllegalArgumentException("Invalid scope value."); 139 } 140 } 141 142 143 /** 144 * Retrieves the value of the attribute with the given name in 145 * the scope occurring earliest in the search order. The order 146 * is determined by the numeric value of the scope parameter (lowest 147 * scope values first.) 148 * 149 * @param name The name of the attribute to retrieve. 150 * @return The value of the attribute in the lowest scope for 151 * which an attribute with the given name is defined. Returns 152 * null if no attribute with the name exists in any scope. 153 * @throws NullPointerException if the name is null. 154 * @throws IllegalArgumentException if the name is empty. 155 */ getAttribute(String name)156 public Object getAttribute(String name) { 157 checkName(name); 158 if (engineScope.containsKey(name)) { 159 return getAttribute(name, ENGINE_SCOPE); 160 } else if (globalScope != null && globalScope.containsKey(name)) { 161 return getAttribute(name, GLOBAL_SCOPE); 162 } 163 164 return null; 165 } 166 167 /** 168 * Gets the value of an attribute in a given scope. 169 * 170 * @param name The name of the attribute to retrieve. 171 * @param scope The scope in which to retrieve the attribute. 172 * @return The value of the attribute. Returns <code>null</code> is the name 173 * does not exist in the given scope. 174 * 175 * @throws IllegalArgumentException 176 * if the name is empty or if the value of scope is invalid. 177 * @throws NullPointerException if the name is null. 178 */ getAttribute(String name, int scope)179 public Object getAttribute(String name, int scope) { 180 checkName(name); 181 switch (scope) { 182 183 case ENGINE_SCOPE: 184 return engineScope.get(name); 185 186 case GLOBAL_SCOPE: 187 if (globalScope != null) { 188 return globalScope.get(name); 189 } 190 return null; 191 192 default: 193 throw new IllegalArgumentException("Illegal scope value."); 194 } 195 } 196 197 /** 198 * Remove an attribute in a given scope. 199 * 200 * @param name The name of the attribute to remove 201 * @param scope The scope in which to remove the attribute 202 * 203 * @return The removed value. 204 * @throws IllegalArgumentException 205 * if the name is empty or if the scope is invalid. 206 * @throws NullPointerException if the name is null. 207 */ removeAttribute(String name, int scope)208 public Object removeAttribute(String name, int scope) { 209 checkName(name); 210 switch (scope) { 211 212 case ENGINE_SCOPE: 213 if (getBindings(ENGINE_SCOPE) != null) { 214 return getBindings(ENGINE_SCOPE).remove(name); 215 } 216 return null; 217 218 case GLOBAL_SCOPE: 219 if (getBindings(GLOBAL_SCOPE) != null) { 220 return getBindings(GLOBAL_SCOPE).remove(name); 221 } 222 return null; 223 224 default: 225 throw new IllegalArgumentException("Illegal scope value."); 226 } 227 } 228 229 /** 230 * Sets the value of an attribute in a given scope. If the scope is <code>GLOBAL_SCOPE</code> 231 * and no Bindings is set for <code>GLOBAL_SCOPE</code>, then setAttribute call is a no-op. 232 * 233 * @param name The name of the attribute to set 234 * @param value The value of the attribute 235 * @param scope The scope in which to set the attribute 236 * 237 * @throws IllegalArgumentException 238 * if the name is empty or if the scope is invalid. 239 * @throws NullPointerException if the name is null. 240 */ setAttribute(String name, Object value, int scope)241 public void setAttribute(String name, Object value, int scope) { 242 checkName(name); 243 switch (scope) { 244 245 case ENGINE_SCOPE: 246 engineScope.put(name, value); 247 return; 248 249 case GLOBAL_SCOPE: 250 if (globalScope != null) { 251 globalScope.put(name, value); 252 } 253 return; 254 255 default: 256 throw new IllegalArgumentException("Illegal scope value."); 257 } 258 } 259 260 /** {@inheritDoc} */ getWriter()261 public Writer getWriter() { 262 return writer; 263 } 264 265 /** {@inheritDoc} */ getReader()266 public Reader getReader() { 267 return reader; 268 } 269 270 /** {@inheritDoc} */ setReader(Reader reader)271 public void setReader(Reader reader) { 272 this.reader = reader; 273 } 274 275 /** {@inheritDoc} */ setWriter(Writer writer)276 public void setWriter(Writer writer) { 277 this.writer = writer; 278 } 279 280 /** {@inheritDoc} */ getErrorWriter()281 public Writer getErrorWriter() { 282 return errorWriter; 283 } 284 285 /** {@inheritDoc} */ setErrorWriter(Writer writer)286 public void setErrorWriter(Writer writer) { 287 this.errorWriter = writer; 288 } 289 290 /** 291 * Get the lowest scope in which an attribute is defined. 292 * @param name Name of the attribute 293 * . 294 * @return The lowest scope. Returns -1 if no attribute with the given 295 * name is defined in any scope. 296 * @throws NullPointerException if name is null. 297 * @throws IllegalArgumentException if name is empty. 298 */ getAttributesScope(String name)299 public int getAttributesScope(String name) { 300 checkName(name); 301 if (engineScope.containsKey(name)) { 302 return ENGINE_SCOPE; 303 } else if (globalScope != null && globalScope.containsKey(name)) { 304 return GLOBAL_SCOPE; 305 } else { 306 return -1; 307 } 308 } 309 310 /** 311 * Returns the value of the <code>engineScope</code> field if specified scope is 312 * <code>ENGINE_SCOPE</code>. Returns the value of the <code>globalScope</code> field if the specified scope is 313 * <code>GLOBAL_SCOPE</code>. 314 * 315 * @param scope The specified scope 316 * @return The value of either the <code>engineScope</code> or <code>globalScope</code> field. 317 * @throws IllegalArgumentException if the value of scope is invalid. 318 */ getBindings(int scope)319 public Bindings getBindings(int scope) { 320 if (scope == ENGINE_SCOPE) { 321 return engineScope; 322 } else if (scope == GLOBAL_SCOPE) { 323 return globalScope; 324 } else { 325 throw new IllegalArgumentException("Illegal scope value."); 326 } 327 } 328 329 /** {@inheritDoc} */ getScopes()330 public List<Integer> getScopes() { 331 return scopes; 332 } 333 checkName(String name)334 private void checkName(String name) { 335 Objects.requireNonNull(name); 336 if (name.isEmpty()) { 337 throw new IllegalArgumentException("name cannot be empty"); 338 } 339 } 340 341 private static List<Integer> scopes; 342 static { 343 scopes = new ArrayList<Integer>(2); 344 scopes.add(ENGINE_SCOPE); 345 scopes.add(GLOBAL_SCOPE); 346 scopes = Collections.unmodifiableList(scopes); 347 } 348 } 349