8264326: Modernize javax.script.ScriptEngineManager and related classes' implementation
Reviewed-by: sundar
This commit is contained in:
parent
b08d6383b9
commit
2bd80f94a1
@ -25,8 +25,6 @@
|
||||
|
||||
package javax.script;
|
||||
import java.io.Reader;
|
||||
import java.util.Map;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Provides a standard implementation for several of the variants of the <code>eval</code>
|
||||
@ -141,9 +139,9 @@ public abstract class AbstractScriptEngine implements ScriptEngine {
|
||||
public void setBindings(Bindings bindings, int scope) {
|
||||
|
||||
if (scope == ScriptContext.GLOBAL_SCOPE) {
|
||||
context.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);;
|
||||
context.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
|
||||
} else if (scope == ScriptContext.ENGINE_SCOPE) {
|
||||
context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);;
|
||||
context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid scope value.");
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ import java.util.*;
|
||||
import java.security.*;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The <code>ScriptEngineManager</code> implements a discovery and instantiation
|
||||
@ -58,8 +60,7 @@ public class ScriptEngineManager {
|
||||
* @see java.lang.Thread#getContextClassLoader
|
||||
*/
|
||||
public ScriptEngineManager() {
|
||||
ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader();
|
||||
init(ctxtLoader);
|
||||
this(Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,18 +73,6 @@ public class ScriptEngineManager {
|
||||
* @param loader ClassLoader used to discover script engine factories.
|
||||
*/
|
||||
public ScriptEngineManager(ClassLoader loader) {
|
||||
init(loader);
|
||||
}
|
||||
|
||||
private void init(final ClassLoader loader) {
|
||||
globalScope = new SimpleBindings();
|
||||
engineSpis = new TreeSet<ScriptEngineFactory>(Comparator.comparing(
|
||||
ScriptEngineFactory::getEngineName,
|
||||
Comparator.nullsLast(Comparator.naturalOrder()))
|
||||
);
|
||||
nameAssociations = new HashMap<String, ScriptEngineFactory>();
|
||||
extensionAssociations = new HashMap<String, ScriptEngineFactory>();
|
||||
mimeTypeAssociations = new HashMap<String, ScriptEngineFactory>();
|
||||
initEngines(loader);
|
||||
}
|
||||
|
||||
@ -96,23 +85,13 @@ public class ScriptEngineManager {
|
||||
}
|
||||
|
||||
private void initEngines(final ClassLoader loader) {
|
||||
Iterator<ScriptEngineFactory> itr = null;
|
||||
Iterator<ScriptEngineFactory> itr;
|
||||
try {
|
||||
ServiceLoader<ScriptEngineFactory> sl = AccessController.doPrivileged(
|
||||
new PrivilegedAction<ServiceLoader<ScriptEngineFactory>>() {
|
||||
@Override
|
||||
public ServiceLoader<ScriptEngineFactory> run() {
|
||||
return getServiceLoader(loader);
|
||||
}
|
||||
});
|
||||
|
||||
var sl = AccessController.doPrivileged(
|
||||
(PrivilegedAction<ServiceLoader<ScriptEngineFactory>>)() -> getServiceLoader(loader));
|
||||
itr = sl.iterator();
|
||||
} catch (ServiceConfigurationError err) {
|
||||
System.err.println("Can't find ScriptEngineFactory providers: " +
|
||||
err.getMessage());
|
||||
if (DEBUG) {
|
||||
err.printStackTrace();
|
||||
}
|
||||
reportException("Can't find ScriptEngineFactory providers: ", err);
|
||||
// do not throw any exception here. user may want to
|
||||
// manage his/her own factories using this manager
|
||||
// by explicit registratation (by registerXXX) methods.
|
||||
@ -125,25 +104,15 @@ public class ScriptEngineManager {
|
||||
ScriptEngineFactory fact = itr.next();
|
||||
engineSpis.add(fact);
|
||||
} catch (ServiceConfigurationError err) {
|
||||
System.err.println("ScriptEngineManager providers.next(): "
|
||||
+ err.getMessage());
|
||||
if (DEBUG) {
|
||||
err.printStackTrace();
|
||||
}
|
||||
reportException("ScriptEngineManager providers.next(): ", err);
|
||||
// one factory failed, but check other factories...
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (ServiceConfigurationError err) {
|
||||
System.err.println("ScriptEngineManager providers.hasNext(): "
|
||||
+ err.getMessage());
|
||||
if (DEBUG) {
|
||||
err.printStackTrace();
|
||||
}
|
||||
reportException("ScriptEngineManager providers.hasNext(): ", err);
|
||||
// do not throw any exception here. user may want to
|
||||
// manage his/her own factories using this manager
|
||||
// by explicit registratation (by registerXXX) methods.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,44 +181,7 @@ public class ScriptEngineManager {
|
||||
* @throws NullPointerException if shortName is null.
|
||||
*/
|
||||
public ScriptEngine getEngineByName(String shortName) {
|
||||
if (shortName == null) throw new NullPointerException();
|
||||
//look for registered name first
|
||||
Object obj;
|
||||
if (null != (obj = nameAssociations.get(shortName))) {
|
||||
ScriptEngineFactory spi = (ScriptEngineFactory)obj;
|
||||
try {
|
||||
ScriptEngine engine = spi.getScriptEngine();
|
||||
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
|
||||
return engine;
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) exp.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
for (ScriptEngineFactory spi : engineSpis) {
|
||||
List<String> names = null;
|
||||
try {
|
||||
names = spi.getNames();
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) exp.printStackTrace();
|
||||
}
|
||||
|
||||
if (names != null) {
|
||||
for (String name : names) {
|
||||
if (shortName.equals(name)) {
|
||||
try {
|
||||
ScriptEngine engine = spi.getScriptEngine();
|
||||
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
|
||||
return engine;
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) exp.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return getEngineBy(shortName, nameAssociations, ScriptEngineFactory::getNames);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -263,41 +195,7 @@ public class ScriptEngineManager {
|
||||
* @throws NullPointerException if extension is null.
|
||||
*/
|
||||
public ScriptEngine getEngineByExtension(String extension) {
|
||||
if (extension == null) throw new NullPointerException();
|
||||
//look for registered extension first
|
||||
Object obj;
|
||||
if (null != (obj = extensionAssociations.get(extension))) {
|
||||
ScriptEngineFactory spi = (ScriptEngineFactory)obj;
|
||||
try {
|
||||
ScriptEngine engine = spi.getScriptEngine();
|
||||
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
|
||||
return engine;
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) exp.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
for (ScriptEngineFactory spi : engineSpis) {
|
||||
List<String> exts = null;
|
||||
try {
|
||||
exts = spi.getExtensions();
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) exp.printStackTrace();
|
||||
}
|
||||
if (exts == null) continue;
|
||||
for (String ext : exts) {
|
||||
if (extension.equals(ext)) {
|
||||
try {
|
||||
ScriptEngine engine = spi.getScriptEngine();
|
||||
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
|
||||
return engine;
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) exp.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return getEngineBy(extension, extensionAssociations, ScriptEngineFactory::getExtensions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -311,41 +209,52 @@ public class ScriptEngineManager {
|
||||
* @throws NullPointerException if mimeType is null.
|
||||
*/
|
||||
public ScriptEngine getEngineByMimeType(String mimeType) {
|
||||
if (mimeType == null) throw new NullPointerException();
|
||||
//look for registered types first
|
||||
Object obj;
|
||||
if (null != (obj = mimeTypeAssociations.get(mimeType))) {
|
||||
ScriptEngineFactory spi = (ScriptEngineFactory)obj;
|
||||
try {
|
||||
ScriptEngine engine = spi.getScriptEngine();
|
||||
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
|
||||
return engine;
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) exp.printStackTrace();
|
||||
}
|
||||
}
|
||||
return getEngineBy(mimeType, mimeTypeAssociations, ScriptEngineFactory::getMimeTypes);
|
||||
}
|
||||
|
||||
for (ScriptEngineFactory spi : engineSpis) {
|
||||
List<String> types = null;
|
||||
try {
|
||||
types = spi.getMimeTypes();
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) exp.printStackTrace();
|
||||
}
|
||||
if (types == null) continue;
|
||||
for (String type : types) {
|
||||
if (mimeType.equals(type)) {
|
||||
try {
|
||||
ScriptEngine engine = spi.getScriptEngine();
|
||||
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
|
||||
return engine;
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) exp.printStackTrace();
|
||||
}
|
||||
private ScriptEngine getEngineBy(String selector, Map<String, ScriptEngineFactory> associations,
|
||||
Function<ScriptEngineFactory, List<String>> valuesFn)
|
||||
{
|
||||
Objects.requireNonNull(selector);
|
||||
Stream<ScriptEngineFactory> spis = Stream.concat(
|
||||
//look for registered types first
|
||||
Stream.ofNullable(associations.get(selector)),
|
||||
|
||||
engineSpis.stream().filter(spi -> {
|
||||
try {
|
||||
List<String> matches = valuesFn.apply(spi);
|
||||
return matches != null && matches.contains(selector);
|
||||
} catch (Exception exp) {
|
||||
debugPrint(exp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
return spis
|
||||
.map(spi -> {
|
||||
try {
|
||||
ScriptEngine engine = spi.getScriptEngine();
|
||||
engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
|
||||
return engine;
|
||||
} catch (Exception exp) {
|
||||
debugPrint(exp);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static void reportException(String msg, Throwable exp) {
|
||||
System.err.println(msg + exp.getMessage());
|
||||
debugPrint(exp);
|
||||
}
|
||||
|
||||
private static void debugPrint(Throwable exp) {
|
||||
if (DEBUG) {
|
||||
exp.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -354,11 +263,7 @@ public class ScriptEngineManager {
|
||||
* @return List of all discovered <code>ScriptEngineFactory</code>s.
|
||||
*/
|
||||
public List<ScriptEngineFactory> getEngineFactories() {
|
||||
List<ScriptEngineFactory> res = new ArrayList<ScriptEngineFactory>(engineSpis.size());
|
||||
for (ScriptEngineFactory spi : engineSpis) {
|
||||
res.add(spi);
|
||||
}
|
||||
return Collections.unmodifiableList(res);
|
||||
return List.copyOf(engineSpis);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -369,8 +274,7 @@ public class ScriptEngineManager {
|
||||
* @throws NullPointerException if any of the parameters is null.
|
||||
*/
|
||||
public void registerEngineName(String name, ScriptEngineFactory factory) {
|
||||
if (name == null || factory == null) throw new NullPointerException();
|
||||
nameAssociations.put(name, factory);
|
||||
associateFactory(nameAssociations, name, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -384,8 +288,7 @@ public class ScriptEngineManager {
|
||||
* @throws NullPointerException if any of the parameters is null.
|
||||
*/
|
||||
public void registerEngineMimeType(String type, ScriptEngineFactory factory) {
|
||||
if (type == null || factory == null) throw new NullPointerException();
|
||||
mimeTypeAssociations.put(type, factory);
|
||||
associateFactory(mimeTypeAssociations, type, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -398,22 +301,33 @@ public class ScriptEngineManager {
|
||||
* @throws NullPointerException if any of the parameters is null.
|
||||
*/
|
||||
public void registerEngineExtension(String extension, ScriptEngineFactory factory) {
|
||||
if (extension == null || factory == null) throw new NullPointerException();
|
||||
extensionAssociations.put(extension, factory);
|
||||
associateFactory(extensionAssociations, extension, factory);
|
||||
}
|
||||
|
||||
private static void associateFactory(Map<String, ScriptEngineFactory> associations, String association,
|
||||
ScriptEngineFactory factory)
|
||||
{
|
||||
if (association == null || factory == null) throw new NullPointerException();
|
||||
associations.put(association, factory);
|
||||
}
|
||||
|
||||
private static final Comparator<ScriptEngineFactory> COMPARATOR = Comparator.comparing(
|
||||
ScriptEngineFactory::getEngineName,
|
||||
Comparator.nullsLast(Comparator.naturalOrder())
|
||||
);
|
||||
|
||||
/** Set of script engine factories discovered. */
|
||||
private TreeSet<ScriptEngineFactory> engineSpis;
|
||||
private final TreeSet<ScriptEngineFactory> engineSpis = new TreeSet<>(COMPARATOR);
|
||||
|
||||
/** Map of engine name to script engine factory. */
|
||||
private HashMap<String, ScriptEngineFactory> nameAssociations;
|
||||
private final HashMap<String, ScriptEngineFactory> nameAssociations = new HashMap<>();
|
||||
|
||||
/** Map of script file extension to script engine factory. */
|
||||
private HashMap<String, ScriptEngineFactory> extensionAssociations;
|
||||
private final HashMap<String, ScriptEngineFactory> extensionAssociations = new HashMap<>();
|
||||
|
||||
/** Map of script MIME type to script engine factory. */
|
||||
private HashMap<String, ScriptEngineFactory> mimeTypeAssociations;
|
||||
private final HashMap<String, ScriptEngineFactory> mimeTypeAssociations = new HashMap<>();
|
||||
|
||||
/** Global bindings associated with script engines created by this manager. */
|
||||
private Bindings globalScope;
|
||||
private Bindings globalScope = new SimpleBindings();
|
||||
}
|
||||
|
@ -38,9 +38,9 @@ public class ScriptException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 8265071037049225001L;
|
||||
|
||||
private String fileName;
|
||||
private int lineNumber;
|
||||
private int columnNumber;
|
||||
private final String fileName;
|
||||
private final int lineNumber;
|
||||
private final int columnNumber;
|
||||
|
||||
/**
|
||||
* Creates a <code>ScriptException</code> with a String to be used in its message.
|
||||
|
@ -28,6 +28,7 @@ package javax.script;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -42,7 +43,7 @@ public class SimpleBindings implements Bindings {
|
||||
/**
|
||||
* The {@code Map} field stores the attributes.
|
||||
*/
|
||||
private Map<String,Object> map;
|
||||
private final Map<String,Object> map;
|
||||
|
||||
/**
|
||||
* Constructor uses an existing {@code Map} to store the values.
|
||||
@ -50,17 +51,14 @@ public class SimpleBindings implements Bindings {
|
||||
* @throws NullPointerException if m is null
|
||||
*/
|
||||
public SimpleBindings(Map<String,Object> m) {
|
||||
if (m == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.map = m;
|
||||
this.map = Objects.requireNonNull(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor uses a {@code HashMap}.
|
||||
*/
|
||||
public SimpleBindings() {
|
||||
this(new HashMap<String,Object>());
|
||||
this(new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,9 +89,7 @@ public class SimpleBindings implements Bindings {
|
||||
* if some key in the map is an empty String.
|
||||
*/
|
||||
public void putAll(Map<? extends String, ? extends Object> toMerge) {
|
||||
if (toMerge == null) {
|
||||
throw new NullPointerException("toMerge map is null");
|
||||
}
|
||||
Objects.requireNonNull(toMerge, "toMerge map is null");
|
||||
for (Map.Entry<? extends String, ? extends Object> entry : toMerge.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
checkKey(key);
|
||||
@ -211,9 +207,7 @@ public class SimpleBindings implements Bindings {
|
||||
}
|
||||
|
||||
private void checkKey(Object key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key can not be null");
|
||||
}
|
||||
Objects.requireNonNull(key, "key can not be null");
|
||||
if (!(key instanceof String)) {
|
||||
throw new ClassCastException("key should be a String");
|
||||
}
|
||||
|
@ -338,11 +338,5 @@ public class SimpleScriptContext implements ScriptContext {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Integer> scopes;
|
||||
static {
|
||||
scopes = new ArrayList<Integer>(2);
|
||||
scopes.add(ENGINE_SCOPE);
|
||||
scopes.add(GLOBAL_SCOPE);
|
||||
scopes = Collections.unmodifiableList(scopes);
|
||||
}
|
||||
private static final List<Integer> scopes = List.of(ENGINE_SCOPE, GLOBAL_SCOPE);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user