KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > script > ScriptEngineManager


1 /*
2  * @(#)ScriptEngineManager.java 1.6 06/04/21 17:44:33
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTAIL. Use is subject to license terms.
6  */

7
8 package javax.script;
9 import java.util.*;
10 import java.net.URL JavaDoc;
11 import java.io.*;
12 import java.security.*;
13 import sun.misc.Service;
14 import sun.misc.ServiceConfigurationError;
15 import sun.reflect.Reflection;
16 import sun.security.util.SecurityConstants;
17
18 /**
19  * The <code>ScriptEngineManager</code> implements a discovery and instantiation
20  * mechanism for <code>ScriptEngine</code> classes and also maintains a
21  * collection of key/value pairs storing state shared by all engines created
22  * by the Manager. This class uses the <a HREF="../../../technotes/guides/jar/jar.html#Service%20Provider">service provider</a> mechanism to enumerate all the
23  * implementations of <code>ScriptEngineFactory</code>. <br><br>
24  * The <code>ScriptEngineManager</code> provides a method to return an array of all these factories
25  * as well as utility methods which look up factories on the basis of language name, file extension
26  * and mime type.
27  * <p>
28  * The <code>Bindings</code> of key/value pairs, referred to as the "Global Scope" maintained
29  * by the manager is available to all instances of <code>ScriptEngine</code> created
30  * by the <code>ScriptEngineManager</code>. The values in the <code>Bindings</code> are
31  * generally exposed in all scripts.
32  *
33  * @author Mike Grogan
34  * @author A. Sundararajan
35  * @since 1.6
36  */

37 public class ScriptEngineManager {
38     private static final boolean DEBUG = false;
39     /**
40      * If the thread context ClassLoader can be accessed by the caller,
41      * then the effect of calling this constructor is the same as calling
42      * <code>ScriptEngineManager(Thread.currentThread().getContextClassLoader())</code>.
43      * Otherwise, the effect is the same as calling <code>ScriptEngineManager(null)</code>.
44      *
45      * @see java.lang.Thread#getContextClassLoader
46      */

47     public ScriptEngineManager() {
48         ClassLoader JavaDoc ctxtLoader = Thread.currentThread().getContextClassLoader();
49         if (canCallerAccessLoader(ctxtLoader)) {
50             if (DEBUG) System.out.println("using " + ctxtLoader);
51             init(ctxtLoader);
52         } else {
53             if (DEBUG) System.out.println("using bootstrap loader");
54             init(null);
55         }
56     }
57     
58     /**
59      * This constructor loads the implementations of
60      * <code>ScriptEngineFactory</code> visible to the given
61      * <code>ClassLoader</code> using the <a HREF="../../../technotes/guides/jar/jar.html#Service%20Provider">service provider</a> mechanism.<br><br>
62      * If loader is <code>null</code>, the script engine factories that are
63      * bundled with the platform and that are in the usual extension
64      * directories (installed extensions) are loaded. <br><br>
65      *
66      * @param loader ClassLoader used to discover script engine factories.
67      */

68     public ScriptEngineManager(ClassLoader JavaDoc loader) {
69         init(loader);
70     }
71     
72     private void init(final ClassLoader JavaDoc loader) {
73         globalScope = new SimpleBindings();
74         engineSpis = new HashSet<ScriptEngineFactory>();
75         nameAssociations = new HashMap<String JavaDoc, ScriptEngineFactory>();
76         extensionAssociations = new HashMap<String JavaDoc, ScriptEngineFactory>();
77         mimeTypeAssociations = new HashMap<String JavaDoc, ScriptEngineFactory>();
78         AccessController.doPrivileged(new PrivilegedAction() {
79             public Object JavaDoc run() {
80                 initEngines(loader);
81                 return null;
82             }
83         });
84     }
85
86     private void initEngines(final ClassLoader JavaDoc loader) {
87         Iterator itr = null;
88         try {
89             if (loader != null) {
90                 itr = Service.providers(ScriptEngineFactory.class, loader);
91             } else {
92                 itr = Service.installedProviders(ScriptEngineFactory.class);
93             }
94         } catch (ServiceConfigurationError err) {
95             System.err.println("Can't find ScriptEngineFactory providers: " +
96                           err.getMessage());
97             if (DEBUG) {
98                 err.printStackTrace();
99             }
100             // do not throw any exception here. user may want to
101
// manage his/her own factories using this manager
102
// by explicit registratation (by registerXXX) methods.
103
return;
104         }
105
106         try {
107             while (itr.hasNext()) {
108                 try {
109                     ScriptEngineFactory fact = (ScriptEngineFactory) itr.next();
110                     engineSpis.add(fact);
111                 } catch (ServiceConfigurationError err) {
112                     System.err.println("ScriptEngineManager providers.next(): "
113                                  + err.getMessage());
114                     if (DEBUG) {
115                         err.printStackTrace();
116                     }
117                     // one factory failed, but check other factories...
118
continue;
119                 }
120             }
121         } catch (ServiceConfigurationError err) {
122             System.err.println("ScriptEngineManager providers.hasNext(): "
123                             + err.getMessage());
124             if (DEBUG) {
125                 err.printStackTrace();
126             }
127             // do not throw any exception here. user may want to
128
// manage his/her own factories using this manager
129
// by explicit registratation (by registerXXX) methods.
130
return;
131         }
132     }
133     
134     /**
135      * <code>setBindings</code> stores the specified <code>Bindings</code>
136      * in the <code>globalScope</code> field. ScriptEngineManager sets this
137      * <code>Bindings</code> as global bindings for <code>ScriptEngine</code>
138      * objects created by it.
139      *
140      * @param bindings The specified <code>Bindings</code>
141      * @throws IllegalArgumentException if bindings is null.
142      */

143     public void setBindings(Bindings bindings) {
144         if (bindings == null) {
145             throw new IllegalArgumentException JavaDoc("Global scope cannot be null.");
146         }
147         
148         globalScope = bindings;
149     }
150     
151     /**
152      * <code>getBindings</code> returns the value of the <code>globalScope</code> field.
153      * ScriptEngineManager sets this <code>Bindings</code> as global bindings for
154      * <code>ScriptEngine</code> objects created by it.
155      *
156      * @return The globalScope field.
157      */

158     public Bindings getBindings() {
159         return globalScope;
160     }
161     
162     /**
163      * Sets the specified key/value pair in the Global Scope.
164      * @param key Key to set
165      * @param value Value to set.
166      * @throws NullPointerException if key is null.
167      * @throws IllegalArgumentException if key is empty string.
168      */

169     public void put(String JavaDoc key, Object JavaDoc value) {
170         globalScope.put(key, value);
171     }
172     
173     /**
174      * Gets the value for the specified key in the Global Scope
175      * @param key The key whose value is to be returned.
176      * @return The value for the specified key.
177      */

178     public Object JavaDoc get(String JavaDoc key) {
179         return globalScope.get(key);
180     }
181     
182     /**
183      * Looks up and creates a <code>ScriptEngine</code> for a given name.
184      * The algorithm first searches for a <code>ScriptEngineFactory</code> that has been
185      * registered as a handler for the specified name using the <code>registerEngineName</code>
186      * method.
187      * <br><br> If one is not found, it searches the array of <code>ScriptEngineFactory</code> instances
188      * stored by the constructor for one with the specified name. If a <code>ScriptEngineFactory</code>
189      * is found by either method, it is used to create instance of <code>ScriptEngine</code>.
190      * @param shortName The short name of the <code>ScriptEngine</code> implementation.
191      * returned by the <code>getNames</code> method of its <code>ScriptEngineFactory</code>.
192      * @return A <code>ScriptEngine</code> created by the factory located in the search. Returns null
193      * if no such factory was found. The <code>ScriptEngineManager</code> sets its own <code>globalScope</code>
194      * <code>Bindings</code> as the <code>GLOBAL_SCOPE</code> <code>Bindings</code> of the newly
195      * created <code>ScriptEngine</code>.
196      * @throws NullPointerException if shortName is null.
197      */

198     public ScriptEngine getEngineByName(String JavaDoc shortName) {
199         if (shortName == null) throw new NullPointerException JavaDoc();
200         //look for registered name first
201
Object JavaDoc obj;
202         if (null != (obj = nameAssociations.get(shortName))) {
203             ScriptEngineFactory spi = (ScriptEngineFactory)obj;
204             try {
205                 ScriptEngine engine = spi.getScriptEngine();
206                 engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
207                 return engine;
208             } catch (Exception JavaDoc exp) {
209                 if (DEBUG) exp.printStackTrace();
210             }
211         }
212         
213         for (ScriptEngineFactory spi : engineSpis) {
214             List<String JavaDoc> names = null;
215             try {
216                 names = spi.getNames();
217             } catch (Exception JavaDoc exp) {
218                 if (DEBUG) exp.printStackTrace();
219             }
220             
221             if (names != null) {
222                 for (String JavaDoc name : names) {
223                     if (shortName.equals(name)) {
224                         try {
225                             ScriptEngine engine = spi.getScriptEngine();
226                             engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
227                             return engine;
228                         } catch (Exception JavaDoc exp) {
229                             if (DEBUG) exp.printStackTrace();
230                         }
231                     }
232                 }
233             }
234         }
235         
236         return null;
237     }
238     
239     /**
240      * Look up and create a <code>ScriptEngine</code> for a given extension. The algorithm
241      * used by <code>getEngineByName</code> is used except that the search starts
242      * by looking for a <code>ScriptEngineFactory</code> registered to handle the
243      * given extension using <code>registerEngineExtension</code>.
244      * @param extension The given extension
245      * @return The engine to handle scripts with this extension. Returns <code>null</code>
246      * if not found.
247      * @throws NullPointerException if extension is null.
248      */

249     public ScriptEngine getEngineByExtension(String JavaDoc extension) {
250         if (extension == null) throw new NullPointerException JavaDoc();
251         //look for registered extension first
252
Object JavaDoc obj;
253         if (null != (obj = extensionAssociations.get(extension))) {
254             ScriptEngineFactory spi = (ScriptEngineFactory)obj;
255             try {
256                 ScriptEngine engine = spi.getScriptEngine();
257                 engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
258                 return engine;
259             } catch (Exception JavaDoc exp) {
260                 if (DEBUG) exp.printStackTrace();
261             }
262         }
263         
264         for (ScriptEngineFactory spi : engineSpis) {
265             List<String JavaDoc> exts = null;
266             try {
267                 exts = spi.getExtensions();
268             } catch (Exception JavaDoc exp) {
269                 if (DEBUG) exp.printStackTrace();
270             }
271             if (exts == null) continue;
272             for (String JavaDoc ext : exts) {
273                 if (extension.equals(ext)) {
274                     try {
275                         ScriptEngine engine = spi.getScriptEngine();
276                         engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
277                         return engine;
278                     } catch (Exception JavaDoc exp) {
279                         if (DEBUG) exp.printStackTrace();
280                     }
281                 }
282             }
283         }
284         return null;
285     }
286     
287     /**
288      * Look up and create a <code>ScriptEngine</code> for a given mime type. The algorithm
289      * used by <code>getEngineByName</code> is used except that the search starts
290      * by looking for a <code>ScriptEngineFactory</code> registered to handle the
291      * given mime type using <code>registerEngineMimeType</code>.
292      * @param mimeType The given mime type
293      * @return The engine to handle scripts with this mime type. Returns <code>null</code>
294      * if not found.
295      * @throws NullPointerException if mimeType is null.
296      */

297     public ScriptEngine getEngineByMimeType(String JavaDoc mimeType) {
298         if (mimeType == null) throw new NullPointerException JavaDoc();
299         //look for registered types first
300
Object JavaDoc obj;
301         if (null != (obj = mimeTypeAssociations.get(mimeType))) {
302             ScriptEngineFactory spi = (ScriptEngineFactory)obj;
303             try {
304                 ScriptEngine engine = spi.getScriptEngine();
305                 engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
306                 return engine;
307             } catch (Exception JavaDoc exp) {
308                 if (DEBUG) exp.printStackTrace();
309             }
310         }
311         
312         for (ScriptEngineFactory spi : engineSpis) {
313             List<String JavaDoc> types = null;
314             try {
315                 types = spi.getMimeTypes();
316             } catch (Exception JavaDoc exp) {
317                 if (DEBUG) exp.printStackTrace();
318             }
319             if (types == null) continue;
320             for (String JavaDoc type : types) {
321                 if (mimeType.equals(type)) {
322                     try {
323                         ScriptEngine engine = spi.getScriptEngine();
324                         engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
325                         return engine;
326                     } catch (Exception JavaDoc exp) {
327                         if (DEBUG) exp.printStackTrace();
328                     }
329                 }
330             }
331         }
332         return null;
333     }
334     
335     /**
336      * Returns an array whose elements are instances of all the <code>ScriptEngineFactory</code> classes
337      * found by the discovery mechanism.
338      * @return List of all discovered <code>ScriptEngineFactory</code>s.
339      */

340     public List<ScriptEngineFactory> getEngineFactories() {
341         List<ScriptEngineFactory> res = new ArrayList<ScriptEngineFactory>(engineSpis.size());
342         for (ScriptEngineFactory spi : engineSpis) {
343             res.add(spi);
344         }
345         return Collections.unmodifiableList(res);
346     }
347     
348     /**
349      * Registers a <code>ScriptEngineFactory</code> to handle a language
350      * name. Overrides any such association found using the Discovery mechanism.
351      * @param name The name to be associated with the <code>ScriptEngineFactory</code>.
352      * @param factory The class to associate with the given name.
353      * @throws NullPointerException if any of the parameters is null.
354      */

355     public void registerEngineName(String JavaDoc name, ScriptEngineFactory factory) {
356         if (name == null || factory == null) throw new NullPointerException JavaDoc();
357         nameAssociations.put(name, factory);
358     }
359     
360     /**
361      * Registers a <code>ScriptEngineFactory</code> to handle a mime type.
362      * Overrides any such association found using the Discovery mechanism.
363      *
364      * @param type The mime type to be associated with the
365      * <code>ScriptEngineFactory</code>.
366      *
367      * @param factory The class to associate with the given mime type.
368      * @throws NullPointerException if any of the parameters is null.
369      */

370     public void registerEngineMimeType(String JavaDoc type, ScriptEngineFactory factory) {
371         if (type == null || factory == null) throw new NullPointerException JavaDoc();
372         mimeTypeAssociations.put(type, factory);
373     }
374     
375     /**
376      * Registers a <code>ScriptEngineFactory</code> to handle an extension.
377      * Overrides any such association found using the Discovery mechanism.
378      *
379      * @param extension The extension type to be associated with the
380      * <code>ScriptEngineFactory</code>.
381      * @param factory The class to associate with the given extension.
382      * @throws NullPointerException if any of the parameters is null.
383      */

384     public void registerEngineExtension(String JavaDoc extension, ScriptEngineFactory factory) {
385         if (extension == null || factory == null) throw new NullPointerException JavaDoc();
386         extensionAssociations.put(extension, factory);
387     }
388     
389     /** Set of script engine factories discovered. */
390     private HashSet<ScriptEngineFactory> engineSpis;
391     
392     /** Map of engine name to script engine factory. */
393     private HashMap<String JavaDoc, ScriptEngineFactory> nameAssociations;
394     
395     /** Map of script file extension to script engine factory. */
396     private HashMap<String JavaDoc, ScriptEngineFactory> extensionAssociations;
397     
398     /** Map of script script MIME type to script engine factory. */
399     private HashMap<String JavaDoc, ScriptEngineFactory> mimeTypeAssociations;
400     
401     /** Global bindings associated with script engines created by this manager. */
402     private Bindings globalScope;
403     
404     private boolean canCallerAccessLoader(ClassLoader JavaDoc loader) {
405         SecurityManager JavaDoc sm = System.getSecurityManager();
406         if (sm != null) {
407             ClassLoader JavaDoc callerLoader = getCallerClassLoader();
408             if (callerLoader != null) {
409                 if (loader != callerLoader || !isAncestor(loader, callerLoader)) {
410                     try {
411                         sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
412                     } catch (SecurityException JavaDoc exp) {
413                         if (DEBUG) exp.printStackTrace();
414                         return false;
415                     }
416                 } // else fallthru..
417
} // else fallthru..
418
} // else fallthru..
419

420         return true;
421     }
422     
423     // Note that this code is same as ClassLoader.getCallerClassLoader().
424
// But, that method is package private and hence we can't call here.
425
private ClassLoader JavaDoc getCallerClassLoader() {
426         Class JavaDoc caller = Reflection.getCallerClass(3);
427         if (caller == null) {
428             return null;
429         }
430         return caller.getClassLoader();
431     }
432     
433     // is cl1 ancestor of cl2?
434
private boolean isAncestor(ClassLoader JavaDoc cl1, ClassLoader JavaDoc cl2) {
435         do {
436             cl2 = cl2.getParent();
437             if (cl1 == cl2) return true;
438         } while (cl2 != null);
439         return false;
440     }
441 }
442
Popular Tags