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
26package javax.script;
27import java.io.Reader;
28import java.util.Map;
29import java.util.Iterator;
30
31/**
32 * Provides a standard implementation for several of the variants of the <code>eval</code>
33 * method.
34 * <br><br>
35 * <code><b>eval(Reader)</b></code><p><code><b>eval(String)</b></code><p>
36 * <code><b>eval(String, Bindings)</b></code><p><code><b>eval(Reader, Bindings)</b></code>
37 * <br><br> are implemented using the abstract methods
38 * <br><br>
39 * <code><b>eval(Reader,ScriptContext)</b></code> or
40 * <code><b>eval(String, ScriptContext)</b></code>
41 * <br><br>
42 * with a <code>SimpleScriptContext</code>.
43 * <br><br>
44 * A <code>SimpleScriptContext</code> is used as the default <code>ScriptContext</code>
45 * of the <code>AbstractScriptEngine</code>..
46 *
47 * @author Mike Grogan
48 * @since 1.6
49 */
50public abstract class AbstractScriptEngine  implements ScriptEngine {
51
52    /**
53     * The default <code>ScriptContext</code> of this <code>AbstractScriptEngine</code>.
54     */
55
56    protected ScriptContext context;
57
58    /**
59     * Creates a new instance of AbstractScriptEngine using a <code>SimpleScriptContext</code>
60     * as its default <code>ScriptContext</code>.
61     */
62    public AbstractScriptEngine() {
63
64        context = new SimpleScriptContext();
65
66    }
67
68    /**
69     * Creates a new instance using the specified <code>Bindings</code> as the
70     * <code>ENGINE_SCOPE</code> <code>Bindings</code> in the protected <code>context</code> field.
71     *
72     * @param n The specified <code>Bindings</code>.
73     * @throws NullPointerException if n is null.
74     */
75    public AbstractScriptEngine(Bindings n) {
76
77        this();
78        if (n == null) {
79            throw new NullPointerException("n is null");
80        }
81        context.setBindings(n, ScriptContext.ENGINE_SCOPE);
82    }
83
84    /**
85     * Sets the value of the protected <code>context</code> field to the specified
86     * <code>ScriptContext</code>.
87     *
88     * @param ctxt The specified <code>ScriptContext</code>.
89     * @throws NullPointerException if ctxt is null.
90     */
91    public void setContext(ScriptContext ctxt) {
92        if (ctxt == null) {
93            throw new NullPointerException("null context");
94        }
95        context = ctxt;
96    }
97
98    /**
99     * Returns the value of the protected <code>context</code> field.
100     *
101     * @return The value of the protected <code>context</code> field.
102     */
103    public ScriptContext getContext() {
104        return context;
105    }
106
107    /**
108     * Returns the <code>Bindings</code> with the specified scope value in
109     * the protected <code>context</code> field.
110     *
111     * @param scope The specified scope
112     *
113     * @return The corresponding <code>Bindings</code>.
114     *
115     * @throws IllegalArgumentException if the value of scope is
116     * invalid for the type the protected <code>context</code> field.
117     */
118    public Bindings getBindings(int scope) {
119
120        if (scope == ScriptContext.GLOBAL_SCOPE) {
121            return context.getBindings(ScriptContext.GLOBAL_SCOPE);
122        } else if (scope == ScriptContext.ENGINE_SCOPE) {
123            return context.getBindings(ScriptContext.ENGINE_SCOPE);
124        } else {
125            throw new IllegalArgumentException("Invalid scope value.");
126        }
127    }
128
129    /**
130     * Sets the <code>Bindings</code> with the corresponding scope value in the
131     * <code>context</code> field.
132     *
133     * @param bindings The specified <code>Bindings</code>.
134     * @param scope The specified scope.
135     *
136     * @throws IllegalArgumentException if the value of scope is
137     * invalid for the type the <code>context</code> field.
138     * @throws NullPointerException if the bindings is null and the scope is
139     * <code>ScriptContext.ENGINE_SCOPE</code>
140     */
141    public void setBindings(Bindings bindings, int scope) {
142
143        if (scope == ScriptContext.GLOBAL_SCOPE) {
144            context.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);;
145        } else if (scope == ScriptContext.ENGINE_SCOPE) {
146            context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);;
147        } else {
148            throw new IllegalArgumentException("Invalid scope value.");
149        }
150    }
151
152    /**
153     * Sets the specified value with the specified key in the <code>ENGINE_SCOPE</code>
154     * <code>Bindings</code> of the protected <code>context</code> field.
155     *
156     * @param key The specified key.
157     * @param value The specified value.
158     *
159     * @throws NullPointerException if key is null.
160     * @throws IllegalArgumentException if key is empty.
161     */
162    public void put(String key, Object value) {
163
164        Bindings nn = getBindings(ScriptContext.ENGINE_SCOPE);
165        if (nn != null) {
166            nn.put(key, value);
167        }
168
169    }
170
171    /**
172     * Gets the value for the specified key in the <code>ENGINE_SCOPE</code> of the
173     * protected <code>context</code> field.
174     *
175     * @return The value for the specified key.
176     *
177     * @throws NullPointerException if key is null.
178     * @throws IllegalArgumentException if key is empty.
179     */
180    public Object get(String key) {
181
182        Bindings nn = getBindings(ScriptContext.ENGINE_SCOPE);
183        if (nn != null) {
184            return nn.get(key);
185        }
186
187        return null;
188    }
189
190
191    /**
192     * <code>eval(Reader, Bindings)</code> calls the abstract
193     * <code>eval(Reader, ScriptContext)</code> method, passing it a <code>ScriptContext</code>
194     * whose Reader, Writers and Bindings for scopes other that <code>ENGINE_SCOPE</code>
195     * are identical to those members of the protected <code>context</code> field.  The specified
196     * <code>Bindings</code> is used instead of the <code>ENGINE_SCOPE</code>
197     *
198     * <code>Bindings</code> of the <code>context</code> field.
199     *
200     * @param reader A <code>Reader</code> containing the source of the script.
201     * @param bindings A <code>Bindings</code> to use for the <code>ENGINE_SCOPE</code>
202     * while the script executes.
203     *
204     * @return The return value from <code>eval(Reader, ScriptContext)</code>
205     * @throws ScriptException if an error occurs in script.
206     * @throws NullPointerException if any of the parameters is null.
207     */
208    public Object eval(Reader reader, Bindings bindings ) throws ScriptException {
209
210        ScriptContext ctxt = getScriptContext(bindings);
211
212        return eval(reader, ctxt);
213    }
214
215
216    /**
217     * Same as <code>eval(Reader, Bindings)</code> except that the abstract
218     * <code>eval(String, ScriptContext)</code> is used.
219     *
220     * @param script A <code>String</code> containing the source of the script.
221     *
222     * @param bindings A <code>Bindings</code> to use as the <code>ENGINE_SCOPE</code>
223     * while the script executes.
224     *
225     * @return The return value from <code>eval(String, ScriptContext)</code>
226     * @throws ScriptException if an error occurs in script.
227     * @throws NullPointerException if any of the parameters is null.
228     */
229    public Object eval(String script, Bindings bindings) throws ScriptException {
230
231        ScriptContext ctxt = getScriptContext(bindings);
232
233        return eval(script , ctxt);
234    }
235
236    /**
237     * <code>eval(Reader)</code> calls the abstract
238     * <code>eval(Reader, ScriptContext)</code> passing the value of the <code>context</code>
239     * field.
240     *
241     * @param reader A <code>Reader</code> containing the source of the script.
242     * @return The return value from <code>eval(Reader, ScriptContext)</code>
243     * @throws ScriptException if an error occurs in script.
244     * @throws NullPointerException if any of the parameters is null.
245     */
246    public Object eval(Reader reader) throws ScriptException {
247
248
249        return eval(reader, context);
250    }
251
252    /**
253     * Same as <code>eval(Reader)</code> except that the abstract
254     * <code>eval(String, ScriptContext)</code> is used.
255     *
256     * @param script A <code>String</code> containing the source of the script.
257     * @return The return value from <code>eval(String, ScriptContext)</code>
258     * @throws ScriptException if an error occurs in script.
259     * @throws NullPointerException if any of the parameters is null.
260     */
261    public Object eval(String script) throws ScriptException {
262
263
264        return eval(script, context);
265    }
266
267    /**
268     * Returns a <code>SimpleScriptContext</code>.  The <code>SimpleScriptContext</code>:
269     *<br><br>
270     * <ul>
271     * <li>Uses the specified <code>Bindings</code> for its <code>ENGINE_SCOPE</code>
272     * </li>
273     * <li>Uses the <code>Bindings</code> returned by the abstract <code>getGlobalScope</code>
274     * method as its <code>GLOBAL_SCOPE</code>
275     * </li>
276     * <li>Uses the Reader and Writer in the default <code>ScriptContext</code> of this
277     * <code>ScriptEngine</code>
278     * </li>
279     * </ul>
280     * <br><br>
281     * A <code>SimpleScriptContext</code> returned by this method is used to implement eval methods
282     * using the abstract <code>eval(Reader,Bindings)</code> and <code>eval(String,Bindings)</code>
283     * versions.
284     *
285     * @param nn Bindings to use for the <code>ENGINE_SCOPE</code>
286     * @return The <code>SimpleScriptContext</code>
287     */
288    protected ScriptContext getScriptContext(Bindings nn) {
289
290        SimpleScriptContext ctxt = new SimpleScriptContext();
291        Bindings gs = getBindings(ScriptContext.GLOBAL_SCOPE);
292
293        if (gs != null) {
294            ctxt.setBindings(gs, ScriptContext.GLOBAL_SCOPE);
295        }
296
297        if (nn != null) {
298            ctxt.setBindings(nn,
299                    ScriptContext.ENGINE_SCOPE);
300        } else {
301            throw new NullPointerException("Engine scope Bindings may not be null.");
302        }
303
304        ctxt.setReader(context.getReader());
305        ctxt.setWriter(context.getWriter());
306        ctxt.setErrorWriter(context.getErrorWriter());
307
308        return ctxt;
309
310    }
311}
312