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