Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.scripting/share/classes/javax/script/ScriptEngineManager.java
41153 views
1
/*
2
* Copyright (c) 2005, 2021, 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.security.*;
29
import java.util.ServiceLoader;
30
import java.util.ServiceConfigurationError;
31
import java.util.function.Function;
32
import java.util.stream.Stream;
33
34
/**
35
* The <code>ScriptEngineManager</code> implements a discovery and instantiation
36
* mechanism for <code>ScriptEngine</code> classes and also maintains a
37
* collection of key/value pairs storing state shared by all engines created
38
* by the Manager. This class uses the service provider mechanism described in the
39
* {@link java.util.ServiceLoader} class to enumerate all the
40
* implementations of <code>ScriptEngineFactory</code>. <br><br>
41
* The <code>ScriptEngineManager</code> provides a method to return a list of all these factories
42
* as well as utility methods which look up factories on the basis of language name, file extension
43
* and mime type.
44
* <p>
45
* The <code>Bindings</code> of key/value pairs, referred to as the "Global Scope" maintained
46
* by the manager is available to all instances of <code>ScriptEngine</code> created
47
* by the <code>ScriptEngineManager</code>. The values in the <code>Bindings</code> are
48
* generally exposed in all scripts.
49
*
50
* @author Mike Grogan
51
* @author A. Sundararajan
52
* @since 1.6
53
*/
54
public class ScriptEngineManager {
55
private static final boolean DEBUG = false;
56
/**
57
* The effect of calling this constructor is the same as calling
58
* <code>ScriptEngineManager(Thread.currentThread().getContextClassLoader())</code>.
59
*
60
* @see java.lang.Thread#getContextClassLoader
61
*/
62
public ScriptEngineManager() {
63
this(Thread.currentThread().getContextClassLoader());
64
}
65
66
/**
67
* This constructor loads the implementations of
68
* <code>ScriptEngineFactory</code> visible to the given
69
* <code>ClassLoader</code> using the service provider mechanism.<br><br>
70
* If loader is <code>null</code>, the script engine factories that are
71
* bundled with the platform are loaded. <br>
72
*
73
* @param loader ClassLoader used to discover script engine factories.
74
*/
75
public ScriptEngineManager(ClassLoader loader) {
76
initEngines(loader);
77
}
78
79
private ServiceLoader<ScriptEngineFactory> getServiceLoader(final ClassLoader loader) {
80
if (loader != null) {
81
return ServiceLoader.load(ScriptEngineFactory.class, loader);
82
} else {
83
return ServiceLoader.loadInstalled(ScriptEngineFactory.class);
84
}
85
}
86
87
private void initEngines(final ClassLoader loader) {
88
Iterator<ScriptEngineFactory> itr;
89
try {
90
@SuppressWarnings("removal")
91
var sl = AccessController.doPrivileged(
92
(PrivilegedAction<ServiceLoader<ScriptEngineFactory>>)() -> getServiceLoader(loader));
93
itr = sl.iterator();
94
} catch (ServiceConfigurationError err) {
95
reportException("Can't find ScriptEngineFactory providers: ", err);
96
// do not throw any exception here. user may want to
97
// manage his/her own factories using this manager
98
// by explicit registratation (by registerXXX) methods.
99
return;
100
}
101
102
try {
103
while (itr.hasNext()) {
104
try {
105
ScriptEngineFactory fact = itr.next();
106
engineSpis.add(fact);
107
} catch (ServiceConfigurationError err) {
108
reportException("ScriptEngineManager providers.next(): ", err);
109
// one factory failed, but check other factories...
110
}
111
}
112
} catch (ServiceConfigurationError err) {
113
reportException("ScriptEngineManager providers.hasNext(): ", err);
114
// do not throw any exception here. user may want to
115
// manage his/her own factories using this manager
116
// by explicit registratation (by registerXXX) methods.
117
}
118
}
119
120
/**
121
* <code>setBindings</code> stores the specified <code>Bindings</code>
122
* in the <code>globalScope</code> field. ScriptEngineManager sets this
123
* <code>Bindings</code> as global bindings for <code>ScriptEngine</code>
124
* objects created by it.
125
*
126
* @param bindings The specified <code>Bindings</code>
127
* @throws IllegalArgumentException if bindings is null.
128
*/
129
public void setBindings(Bindings bindings) {
130
if (bindings == null) {
131
throw new IllegalArgumentException("Global scope cannot be null.");
132
}
133
134
globalScope = bindings;
135
}
136
137
/**
138
* <code>getBindings</code> returns the value of the <code>globalScope</code> field.
139
* ScriptEngineManager sets this <code>Bindings</code> as global bindings for
140
* <code>ScriptEngine</code> objects created by it.
141
*
142
* @return The globalScope field.
143
*/
144
public Bindings getBindings() {
145
return globalScope;
146
}
147
148
/**
149
* Sets the specified key/value pair in the Global Scope.
150
* @param key Key to set
151
* @param value Value to set.
152
* @throws NullPointerException if key is null.
153
* @throws IllegalArgumentException if key is empty string.
154
*/
155
public void put(String key, Object value) {
156
globalScope.put(key, value);
157
}
158
159
/**
160
* Gets the value for the specified key in the Global Scope
161
* @param key The key whose value is to be returned.
162
* @return The value for the specified key.
163
*/
164
public Object get(String key) {
165
return globalScope.get(key);
166
}
167
168
/**
169
* Looks up and creates a <code>ScriptEngine</code> for a given name.
170
* The algorithm first searches for a <code>ScriptEngineFactory</code> that has been
171
* registered as a handler for the specified name using the <code>registerEngineName</code>
172
* method.
173
* <br><br> If one is not found, it searches the set of <code>ScriptEngineFactory</code> instances
174
* stored by the constructor for one with the specified name. If a <code>ScriptEngineFactory</code>
175
* is found by either method, it is used to create instance of <code>ScriptEngine</code>.
176
* @param shortName The short name of the <code>ScriptEngine</code> implementation.
177
* returned by the <code>getNames</code> method of its <code>ScriptEngineFactory</code>.
178
* @return A <code>ScriptEngine</code> created by the factory located in the search. Returns null
179
* if no such factory was found. The <code>ScriptEngineManager</code> sets its own <code>globalScope</code>
180
* <code>Bindings</code> as the <code>GLOBAL_SCOPE</code> <code>Bindings</code> of the newly
181
* created <code>ScriptEngine</code>.
182
* @throws NullPointerException if shortName is null.
183
*/
184
public ScriptEngine getEngineByName(String shortName) {
185
return getEngineBy(shortName, nameAssociations, ScriptEngineFactory::getNames);
186
}
187
188
/**
189
* Look up and create a <code>ScriptEngine</code> for a given extension. The algorithm
190
* used by <code>getEngineByName</code> is used except that the search starts
191
* by looking for a <code>ScriptEngineFactory</code> registered to handle the
192
* given extension using <code>registerEngineExtension</code>.
193
* @param extension The given extension
194
* @return The engine to handle scripts with this extension. Returns <code>null</code>
195
* if not found.
196
* @throws NullPointerException if extension is null.
197
*/
198
public ScriptEngine getEngineByExtension(String extension) {
199
return getEngineBy(extension, extensionAssociations, ScriptEngineFactory::getExtensions);
200
}
201
202
/**
203
* Look up and create a <code>ScriptEngine</code> for a given mime type. The algorithm
204
* used by <code>getEngineByName</code> is used except that the search starts
205
* by looking for a <code>ScriptEngineFactory</code> registered to handle the
206
* given mime type using <code>registerEngineMimeType</code>.
207
* @param mimeType The given mime type
208
* @return The engine to handle scripts with this mime type. Returns <code>null</code>
209
* if not found.
210
* @throws NullPointerException if mimeType is null.
211
*/
212
public ScriptEngine getEngineByMimeType(String mimeType) {
213
return getEngineBy(mimeType, mimeTypeAssociations, ScriptEngineFactory::getMimeTypes);
214
}
215
216
private ScriptEngine getEngineBy(String selector, Map<String, ScriptEngineFactory> associations,
217
Function<ScriptEngineFactory, List<String>> valuesFn)
218
{
219
Objects.requireNonNull(selector);
220
Stream<ScriptEngineFactory> spis = Stream.concat(
221
//look for registered types first
222
Stream.ofNullable(associations.get(selector)),
223
224
engineSpis.stream().filter(spi -> {
225
try {
226
List<String> matches = valuesFn.apply(spi);
227
return matches != null && matches.contains(selector);
228
} catch (Exception exp) {
229
debugPrint(exp);
230
return false;
231
}
232
})
233
);
234
return spis
235
.map(spi -> {
236
try {
237
ScriptEngine engine = spi.getScriptEngine();
238
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
239
return engine;
240
} catch (Exception exp) {
241
debugPrint(exp);
242
return null;
243
}
244
})
245
.filter(Objects::nonNull)
246
.findFirst()
247
.orElse(null);
248
}
249
250
private static void reportException(String msg, Throwable exp) {
251
System.err.println(msg + exp.getMessage());
252
debugPrint(exp);
253
}
254
255
private static void debugPrint(Throwable exp) {
256
if (DEBUG) {
257
exp.printStackTrace();
258
}
259
}
260
261
/**
262
* Returns a list whose elements are instances of all the <code>ScriptEngineFactory</code> classes
263
* found by the discovery mechanism.
264
* @return List of all discovered <code>ScriptEngineFactory</code>s.
265
*/
266
public List<ScriptEngineFactory> getEngineFactories() {
267
return List.copyOf(engineSpis);
268
}
269
270
/**
271
* Registers a <code>ScriptEngineFactory</code> to handle a language
272
* name. Overrides any such association found using the Discovery mechanism.
273
* @param name The name to be associated with the <code>ScriptEngineFactory</code>.
274
* @param factory The class to associate with the given name.
275
* @throws NullPointerException if any of the parameters is null.
276
*/
277
public void registerEngineName(String name, ScriptEngineFactory factory) {
278
associateFactory(nameAssociations, name, factory);
279
}
280
281
/**
282
* Registers a <code>ScriptEngineFactory</code> to handle a mime type.
283
* Overrides any such association found using the Discovery mechanism.
284
*
285
* @param type The mime type to be associated with the
286
* <code>ScriptEngineFactory</code>.
287
*
288
* @param factory The class to associate with the given mime type.
289
* @throws NullPointerException if any of the parameters is null.
290
*/
291
public void registerEngineMimeType(String type, ScriptEngineFactory factory) {
292
associateFactory(mimeTypeAssociations, type, factory);
293
}
294
295
/**
296
* Registers a <code>ScriptEngineFactory</code> to handle an extension.
297
* Overrides any such association found using the Discovery mechanism.
298
*
299
* @param extension The extension type to be associated with the
300
* <code>ScriptEngineFactory</code>.
301
* @param factory The class to associate with the given extension.
302
* @throws NullPointerException if any of the parameters is null.
303
*/
304
public void registerEngineExtension(String extension, ScriptEngineFactory factory) {
305
associateFactory(extensionAssociations, extension, factory);
306
}
307
308
private static void associateFactory(Map<String, ScriptEngineFactory> associations, String association,
309
ScriptEngineFactory factory)
310
{
311
if (association == null || factory == null) throw new NullPointerException();
312
associations.put(association, factory);
313
}
314
315
private static final Comparator<ScriptEngineFactory> COMPARATOR = Comparator.comparing(
316
ScriptEngineFactory::getEngineName,
317
Comparator.nullsLast(Comparator.naturalOrder())
318
);
319
320
/** Set of script engine factories discovered. */
321
private final TreeSet<ScriptEngineFactory> engineSpis = new TreeSet<>(COMPARATOR);
322
323
/** Map of engine name to script engine factory. */
324
private final HashMap<String, ScriptEngineFactory> nameAssociations = new HashMap<>();
325
326
/** Map of script file extension to script engine factory. */
327
private final HashMap<String, ScriptEngineFactory> extensionAssociations = new HashMap<>();
328
329
/** Map of script MIME type to script engine factory. */
330
private final HashMap<String, ScriptEngineFactory> mimeTypeAssociations = new HashMap<>();
331
332
/** Global bindings associated with script engines created by this manager. */
333
private Bindings globalScope = new SimpleBindings();
334
}
335
336