History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/script/ScriptEngineManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/script/ScriptEngineManager.java+459−0
@@ -0,0 +1,459 @@
1+/*
2+ * Copyright (c) 2005, 2006, 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+import java.util.*;
28+import java.net.URL;
29+import java.io.*;
30+import java.security.*;
31+import sun.misc.Service;
32+import sun.misc.ServiceConfigurationError;
33+import sun.reflect.Reflection;
34+import sun.security.util.SecurityConstants;
35+
36+/**
37+ * The <code>ScriptEngineManager</code> implements a discovery and instantiation
38+ * mechanism for <code>ScriptEngine</code> classes and also maintains a
39+ * collection of key/value pairs storing state shared by all engines created
40+ * by the Manager. This class uses the <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">service provider</a> mechanism to enumerate all the
41+ * implementations of <code>ScriptEngineFactory</code>. <br><br>
42+ * The <code>ScriptEngineManager</code> provides a method to return an array of all these factories
43+ * as well as utility methods which look up factories on the basis of language name, file extension
44+ * and mime type.
45+ * <p>
46+ * The <code>Bindings</code> of key/value pairs, referred to as the "Global Scope" maintained
47+ * by the manager is available to all instances of <code>ScriptEngine</code> created
48+ * by the <code>ScriptEngineManager</code>. The values in the <code>Bindings</code> are
49+ * generally exposed in all scripts.
50+ *
51+ * @author Mike Grogan
52+ * @author A. Sundararajan
53+ * @since 1.6
54+ */
55+public class ScriptEngineManager {
56+ private static final boolean DEBUG = false;
57+ /**
58+ * If the thread context ClassLoader can be accessed by the caller,
59+ * then the effect of calling this constructor is the same as calling
60+ * <code>ScriptEngineManager(Thread.currentThread().getContextClassLoader())</code>.
61+ * Otherwise, the effect is the same as calling <code>ScriptEngineManager(null)</code>.
62+ *
63+ * @see java.lang.Thread#getContextClassLoader
64+ */
65+ public ScriptEngineManager() {
66+ ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader();
67+ if (canCallerAccessLoader(ctxtLoader)) {
68+ if (DEBUG) System.out.println("using " + ctxtLoader);
69+ init(ctxtLoader);
70+ } else {
71+ if (DEBUG) System.out.println("using bootstrap loader");
72+ init(null);
73+ }
74+ }
75+
76+ /**
77+ * This constructor loads the implementations of
78+ * <code>ScriptEngineFactory</code> visible to the given
79+ * <code>ClassLoader</code> using the <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">service provider</a> mechanism.<br><br>
80+ * If loader is <code>null</code>, the script engine factories that are
81+ * bundled with the platform and that are in the usual extension
82+ * directories (installed extensions) are loaded. <br><br>
83+ *
84+ * @param loader ClassLoader used to discover script engine factories.
85+ */
86+ public ScriptEngineManager(ClassLoader loader) {
87+ init(loader);
88+ }
89+
90+ private void init(final ClassLoader loader) {
91+ globalScope = new SimpleBindings();
92+ engineSpis = new HashSet<ScriptEngineFactory>();
93+ nameAssociations = new HashMap<String, ScriptEngineFactory>();
94+ extensionAssociations = new HashMap<String, ScriptEngineFactory>();
95+ mimeTypeAssociations = new HashMap<String, ScriptEngineFactory>();
96+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
97+ public Object run() {
98+ initEngines(loader);
99+ return null;
100+ }
101+ });
102+ }
103+
104+ private void initEngines(final ClassLoader loader) {
105+ Iterator itr = null;
106+ try {
107+ if (loader != null) {
108+ itr = Service.providers(ScriptEngineFactory.class, loader);
109+ } else {
110+ itr = Service.installedProviders(ScriptEngineFactory.class);
111+ }
112+ } catch (ServiceConfigurationError err) {
113+ System.err.println("Can't find ScriptEngineFactory providers: " +
114+ err.getMessage());
115+ if (DEBUG) {
116+ err.printStackTrace();
117+ }
118+ // do not throw any exception here. user may want to
119+ // manage his/her own factories using this manager
120+ // by explicit registratation (by registerXXX) methods.
121+ return;
122+ }
123+
124+ try {
125+ while (itr.hasNext()) {
126+ try {
127+ ScriptEngineFactory fact = (ScriptEngineFactory) itr.next();
128+ engineSpis.add(fact);
129+ } catch (ServiceConfigurationError err) {
130+ System.err.println("ScriptEngineManager providers.next(): "
131+ + err.getMessage());
132+ if (DEBUG) {
133+ err.printStackTrace();
134+ }
135+ // one factory failed, but check other factories...
136+ continue;
137+ }
138+ }
139+ } catch (ServiceConfigurationError err) {
140+ System.err.println("ScriptEngineManager providers.hasNext(): "
141+ + err.getMessage());
142+ if (DEBUG) {
143+ err.printStackTrace();
144+ }
145+ // do not throw any exception here. user may want to
146+ // manage his/her own factories using this manager
147+ // by explicit registratation (by registerXXX) methods.
148+ return;
149+ }
150+ }
151+
152+ /**
153+ * <code>setBindings</code> stores the specified <code>Bindings</code>
154+ * in the <code>globalScope</code> field. ScriptEngineManager sets this
155+ * <code>Bindings</code> as global bindings for <code>ScriptEngine</code>
156+ * objects created by it.
157+ *
158+ * @param bindings The specified <code>Bindings</code>
159+ * @throws IllegalArgumentException if bindings is null.
160+ */
161+ public void setBindings(Bindings bindings) {
162+ if (bindings == null) {
163+ throw new IllegalArgumentException("Global scope cannot be null.");
164+ }
165+
166+ globalScope = bindings;
167+ }
168+
169+ /**
170+ * <code>getBindings</code> returns the value of the <code>globalScope</code> field.
171+ * ScriptEngineManager sets this <code>Bindings</code> as global bindings for
172+ * <code>ScriptEngine</code> objects created by it.
173+ *
174+ * @return The globalScope field.
175+ */
176+ public Bindings getBindings() {
177+ return globalScope;
178+ }
179+
180+ /**
181+ * Sets the specified key/value pair in the Global Scope.
182+ * @param key Key to set
183+ * @param value Value to set.
184+ * @throws NullPointerException if key is null.
185+ * @throws IllegalArgumentException if key is empty string.
186+ */
187+ public void put(String key, Object value) {
188+ globalScope.put(key, value);
189+ }
190+
191+ /**
192+ * Gets the value for the specified key in the Global Scope
193+ * @param key The key whose value is to be returned.
194+ * @return The value for the specified key.
195+ */
196+ public Object get(String key) {
197+ return globalScope.get(key);
198+ }
199+
200+ /**
201+ * Looks up and creates a <code>ScriptEngine</code> for a given name.
202+ * The algorithm first searches for a <code>ScriptEngineFactory</code> that has been
203+ * registered as a handler for the specified name using the <code>registerEngineName</code>
204+ * method.
205+ * <br><br> If one is not found, it searches the array of <code>ScriptEngineFactory</code> instances
206+ * stored by the constructor for one with the specified name. If a <code>ScriptEngineFactory</code>
207+ * is found by either method, it is used to create instance of <code>ScriptEngine</code>.
208+ * @param shortName The short name of the <code>ScriptEngine</code> implementation.
209+ * returned by the <code>getNames</code> method of its <code>ScriptEngineFactory</code>.
210+ * @return A <code>ScriptEngine</code> created by the factory located in the search. Returns null
211+ * if no such factory was found. The <code>ScriptEngineManager</code> sets its own <code>globalScope</code>
212+ * <code>Bindings</code> as the <code>GLOBAL_SCOPE</code> <code>Bindings</code> of the newly
213+ * created <code>ScriptEngine</code>.
214+ * @throws NullPointerException if shortName is null.
215+ */
216+ public ScriptEngine getEngineByName(String shortName) {
217+ if (shortName == null) throw new NullPointerException();
218+ //look for registered name first
219+ Object obj;
220+ if (null != (obj = nameAssociations.get(shortName))) {
221+ ScriptEngineFactory spi = (ScriptEngineFactory)obj;
222+ try {
223+ ScriptEngine engine = spi.getScriptEngine();
224+ engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
225+ return engine;
226+ } catch (Exception exp) {
227+ if (DEBUG) exp.printStackTrace();
228+ }
229+ }
230+
231+ for (ScriptEngineFactory spi : engineSpis) {
232+ List<String> names = null;
233+ try {
234+ names = spi.getNames();
235+ } catch (Exception exp) {
236+ if (DEBUG) exp.printStackTrace();
237+ }
238+
239+ if (names != null) {
240+ for (String name : names) {
241+ if (shortName.equals(name)) {
242+ try {
243+ ScriptEngine engine = spi.getScriptEngine();
244+ engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
245+ return engine;
246+ } catch (Exception exp) {
247+ if (DEBUG) exp.printStackTrace();
248+ }
249+ }
250+ }
251+ }
252+ }
253+
254+ return null;
255+ }
256+
257+ /**
258+ * Look up and create a <code>ScriptEngine</code> for a given extension. The algorithm
259+ * used by <code>getEngineByName</code> is used except that the search starts
260+ * by looking for a <code>ScriptEngineFactory</code> registered to handle the
261+ * given extension using <code>registerEngineExtension</code>.
262+ * @param extension The given extension
263+ * @return The engine to handle scripts with this extension. Returns <code>null</code>
264+ * if not found.
265+ * @throws NullPointerException if extension is null.
266+ */
267+ public ScriptEngine getEngineByExtension(String extension) {
268+ if (extension == null) throw new NullPointerException();
269+ //look for registered extension first
270+ Object obj;
271+ if (null != (obj = extensionAssociations.get(extension))) {
272+ ScriptEngineFactory spi = (ScriptEngineFactory)obj;
273+ try {
274+ ScriptEngine engine = spi.getScriptEngine();
275+ engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
276+ return engine;
277+ } catch (Exception exp) {
278+ if (DEBUG) exp.printStackTrace();
279+ }
280+ }
281+
282+ for (ScriptEngineFactory spi : engineSpis) {
283+ List<String> exts = null;
284+ try {
285+ exts = spi.getExtensions();
286+ } catch (Exception exp) {
287+ if (DEBUG) exp.printStackTrace();
288+ }
289+ if (exts == null) continue;
290+ for (String ext : exts) {
291+ if (extension.equals(ext)) {
292+ try {
293+ ScriptEngine engine = spi.getScriptEngine();
294+ engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
295+ return engine;
296+ } catch (Exception exp) {
297+ if (DEBUG) exp.printStackTrace();
298+ }
299+ }
300+ }
301+ }
302+ return null;
303+ }
304+
305+ /**
306+ * Look up and create a <code>ScriptEngine</code> for a given mime type. The algorithm
307+ * used by <code>getEngineByName</code> is used except that the search starts
308+ * by looking for a <code>ScriptEngineFactory</code> registered to handle the
309+ * given mime type using <code>registerEngineMimeType</code>.
310+ * @param mimeType The given mime type
311+ * @return The engine to handle scripts with this mime type. Returns <code>null</code>
312+ * if not found.
313+ * @throws NullPointerException if mimeType is null.
314+ */
315+ public ScriptEngine getEngineByMimeType(String mimeType) {
316+ if (mimeType == null) throw new NullPointerException();
317+ //look for registered types first
318+ Object obj;
319+ if (null != (obj = mimeTypeAssociations.get(mimeType))) {
320+ ScriptEngineFactory spi = (ScriptEngineFactory)obj;
321+ try {
322+ ScriptEngine engine = spi.getScriptEngine();
323+ engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
324+ return engine;
325+ } catch (Exception exp) {
326+ if (DEBUG) exp.printStackTrace();
327+ }
328+ }
329+
330+ for (ScriptEngineFactory spi : engineSpis) {
331+ List<String> types = null;
332+ try {
333+ types = spi.getMimeTypes();
334+ } catch (Exception exp) {
335+ if (DEBUG) exp.printStackTrace();
336+ }
337+ if (types == null) continue;
338+ for (String type : types) {
339+ if (mimeType.equals(type)) {
340+ try {
341+ ScriptEngine engine = spi.getScriptEngine();
342+ engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
343+ return engine;
344+ } catch (Exception exp) {
345+ if (DEBUG) exp.printStackTrace();
346+ }
347+ }
348+ }
349+ }
350+ return null;
351+ }
352+
353+ /**
354+ * Returns an array whose elements are instances of all the <code>ScriptEngineFactory</code> classes
355+ * found by the discovery mechanism.
356+ * @return List of all discovered <code>ScriptEngineFactory</code>s.
357+ */
358+ public List<ScriptEngineFactory> getEngineFactories() {
359+ List<ScriptEngineFactory> res = new ArrayList<ScriptEngineFactory>(engineSpis.size());
360+ for (ScriptEngineFactory spi : engineSpis) {
361+ res.add(spi);
362+ }
363+ return Collections.unmodifiableList(res);
364+ }
365+
366+ /**
367+ * Registers a <code>ScriptEngineFactory</code> to handle a language
368+ * name. Overrides any such association found using the Discovery mechanism.
369+ * @param name The name to be associated with the <code>ScriptEngineFactory</code>.
370+ * @param factory The class to associate with the given name.
371+ * @throws NullPointerException if any of the parameters is null.
372+ */
373+ public void registerEngineName(String name, ScriptEngineFactory factory) {
374+ if (name == null || factory == null) throw new NullPointerException();
375+ nameAssociations.put(name, factory);
376+ }
377+
378+ /**
379+ * Registers a <code>ScriptEngineFactory</code> to handle a mime type.
380+ * Overrides any such association found using the Discovery mechanism.
381+ *
382+ * @param type The mime type to be associated with the
383+ * <code>ScriptEngineFactory</code>.
384+ *
385+ * @param factory The class to associate with the given mime type.
386+ * @throws NullPointerException if any of the parameters is null.
387+ */
388+ public void registerEngineMimeType(String type, ScriptEngineFactory factory) {
389+ if (type == null || factory == null) throw new NullPointerException();
390+ mimeTypeAssociations.put(type, factory);
391+ }
392+
393+ /**
394+ * Registers a <code>ScriptEngineFactory</code> to handle an extension.
395+ * Overrides any such association found using the Discovery mechanism.
396+ *
397+ * @param extension The extension type to be associated with the
398+ * <code>ScriptEngineFactory</code>.
399+ * @param factory The class to associate with the given extension.
400+ * @throws NullPointerException if any of the parameters is null.
401+ */
402+ public void registerEngineExtension(String extension, ScriptEngineFactory factory) {
403+ if (extension == null || factory == null) throw new NullPointerException();
404+ extensionAssociations.put(extension, factory);
405+ }
406+
407+ /** Set of script engine factories discovered. */
408+ private HashSet<ScriptEngineFactory> engineSpis;
409+
410+ /** Map of engine name to script engine factory. */
411+ private HashMap<String, ScriptEngineFactory> nameAssociations;
412+
413+ /** Map of script file extension to script engine factory. */
414+ private HashMap<String, ScriptEngineFactory> extensionAssociations;
415+
416+ /** Map of script script MIME type to script engine factory. */
417+ private HashMap<String, ScriptEngineFactory> mimeTypeAssociations;
418+
419+ /** Global bindings associated with script engines created by this manager. */
420+ private Bindings globalScope;
421+
422+ private boolean canCallerAccessLoader(ClassLoader loader) {
423+ SecurityManager sm = System.getSecurityManager();
424+ if (sm != null) {
425+ ClassLoader callerLoader = getCallerClassLoader();
426+ if (callerLoader != null) {
427+ if (loader != callerLoader || !isAncestor(loader, callerLoader)) {
428+ try {
429+ sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
430+ } catch (SecurityException exp) {
431+ if (DEBUG) exp.printStackTrace();
432+ return false;
433+ }
434+ } // else fallthru..
435+ } // else fallthru..
436+ } // else fallthru..
437+
438+ return true;
439+ }
440+
441+ // Note that this code is same as ClassLoader.getCallerClassLoader().
442+ // But, that method is package private and hence we can't call here.
443+ private ClassLoader getCallerClassLoader() {
444+ Class caller = Reflection.getCallerClass(3);
445+ if (caller == null) {
446+ return null;
447+ }
448+ return caller.getClassLoader();
449+ }
450+
451+ // is cl1 ancestor of cl2?
452+ private boolean isAncestor(ClassLoader cl1, ClassLoader cl2) {
453+ do {
454+ cl2 = cl2.getParent();
455+ if (cl1 == cl2) return true;
456+ } while (cl2 != null);
457+ return false;
458+ }
459+}