in gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java [549:660]
Object eval(final Class scriptClass, final ScriptContext context) throws ScriptException {
final Binding binding = new Binding(context.getBindings(ScriptContext.ENGINE_SCOPE)) {
@Override
public Object getVariable(String name) {
synchronized (context) {
int scope = context.getAttributesScope(name);
if (scope != -1) {
return context.getAttribute(name, scope);
}
// Redirect script output to context writer, if out var is not already provided
if ("out".equals(name)) {
final Writer writer = context.getWriter();
if (writer != null) {
return (writer instanceof PrintWriter) ?
(PrintWriter) writer :
new PrintWriter(writer, true);
}
}
// Provide access to engine context, if context var is not already provided
if ("context".equals(name)) {
return context;
}
}
throw new MissingPropertyException(name, getClass());
}
@Override
public void setVariable(String name, Object value) {
synchronized (context) {
int scope = context.getAttributesScope(name);
if (scope == -1) {
scope = ScriptContext.ENGINE_SCOPE;
}
context.setAttribute(name, value, scope);
}
}
};
try {
// if this class is not an instance of Script, it's a full-blown class then simply return that class
if (!Script.class.isAssignableFrom(scriptClass)) {
return scriptClass;
} else {
final Script scriptObject = InvokerHelper.createScript(scriptClass, binding);
if (globalFunctionCacheEnabled) {
for (Method m : scriptClass.getMethods()) {
final String name = m.getName();
globalClosures.put(name, new MethodClosure(scriptObject, name));
}
}
final MetaClass oldMetaClass = scriptObject.getMetaClass();
scriptObject.setMetaClass(new DelegatingMetaClass(oldMetaClass) {
@Override
public Object invokeMethod(final Object object, final String name, final Object args) {
if (args == null) {
return invokeMethod(object, name, MetaClassHelper.EMPTY_ARRAY);
} else if (args instanceof Tuple) {
return invokeMethod(object, name, ((Tuple) args).toArray());
} else if (args instanceof Object[]) {
return invokeMethod(object, name, (Object[]) args);
} else {
return invokeMethod(object, name, new Object[]{args});
}
}
@Override
public Object invokeMethod(final Object object, final String name, final Object args[]) {
try {
return super.invokeMethod(object, name, args);
} catch (MissingMethodException mme) {
return callGlobal(name, args, context);
}
}
@Override
public Object invokeStaticMethod(final Object object, final String name, final Object args[]) {
try {
return super.invokeStaticMethod(object, name, args);
} catch (MissingMethodException mme) {
return callGlobal(name, args, context);
}
}
});
final Object o = scriptObject.run();
// if interpreter mode is enable then local vars of the script are promoted to engine scope bindings.
if (interpreterModeEnabled) {
final Map<String, Object> localVars = (Map<String, Object>) context.getAttribute(COLLECTED_BOUND_VARS_MAP_VARNAME);
if (localVars != null) {
localVars.entrySet().forEach(e -> {
// closures need to be cached for later use
if (globalFunctionCacheEnabled && e.getValue() instanceof Closure)
globalClosures.put(e.getKey(), (Closure) e.getValue());
context.setAttribute(e.getKey(), e.getValue(), ScriptContext.ENGINE_SCOPE);
});
// get rid of the temporary collected vars
context.removeAttribute(COLLECTED_BOUND_VARS_MAP_VARNAME, ScriptContext.ENGINE_SCOPE);
localVars.clear();
}
}
return o;
}
} catch (Exception e) {
throw new ScriptException(e);
}
}