blob: f014497820addb2ed93ac1cfdce3f1e472cd0e38 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jena.sparql.function.js;
import javax.script.ScriptException;
import org.apache.jena.atlas.lib.Pool;
import org.apache.jena.atlas.lib.PoolBase;
import org.apache.jena.atlas.lib.PoolSync;
import org.apache.jena.query.ARQ;
import org.apache.jena.sparql.util.Context;
import org.apache.jena.sparql.util.Symbol;
/** Environment for executing a JavaScript function.
* <p>
* Functions are loaded from the file named in context setting
* {@link EnvJavaScript#symJavaScriptLibFile}.
* The file must be UTF-8 encoded.
* <p>
* Function are loaded from a string value in context setting
* {@link EnvJavaScript#symJavaScriptFunctions}.
* <p>
* If both are present, the file named by {@code EnvJavaScript.symJavaScriptLibFile} is loaded
* then the string from {@code EnvJavaScript.symJavaScriptLib}.
*
* @deprecated Use {@link org.apache.jena.sparql.function.scripting.ScriptFunction}
*/
@Deprecated
public class EnvJavaScript {
/** JavaScript functions as a string value which is evaluated. */
public static Symbol symJavaScriptFunctions = ARQ.symJavaScriptFunctions;
/** JavaScript library of functions in a file. */
public static Symbol symJavaScriptLibFile = ARQ.symJavaScriptLibFile;
private final String scriptLib;
private final String scriptLibFile;
public static EnvJavaScript create(Context context) {
return new EnvJavaScript(context);
}
private static volatile EnvJavaScript global = null;
/**
* Return the global {@code EnvJavaScript}.
* Returns null if no JavaScript has been provided.
*/
public static EnvJavaScript get() {
if ( global == null ) {
synchronized(EnvJavaScript.class) {
if ( global == null ) {
Context context = ARQ.getContext();
if ( context.isDefined(symJavaScriptFunctions) || context.isDefined(symJavaScriptLibFile) )
global = create(context);
}
}
}
return global ;
}
/** Reset the global {@code EnvJavaScript} based on the system-wide context */
public static void reset() {
reset(ARQ.getContext());
}
/** Reset the global {@code EnvJavaScript} */
public static void reset(Context context) {
global = create(context);
}
// ---- EnvJavaScript Object
// One script engine per thread, here done by one per usage.
// Nashorn script engines are thread safe but the script Bindings} must not be shared.
// Direct use of Nashorn, via the protected APIs of jdk.nashorn.api.scripting
// are needed to utilize this and having one compiled form and many execution units.
// But in Java8 is saving up problems for Java9 and the
// Nashorn subsystem is imporved at Java9 for this use case.
// For now, in combination with the implementation of JSEngine,
// we keep separate Nashorn script engines.
private final Pool<JSEngine> pool = PoolSync.create(new PoolBase<JSEngine>());
private EnvJavaScript(Context context) {
this.scriptLib = context.getAsString(symJavaScriptFunctions);
this.scriptLibFile = context.getAsString(symJavaScriptLibFile);
// Put one in the pool.
pool.put(build());
}
private JSEngine build() {
return new JSEngine(scriptLib, scriptLibFile);
}
private JSEngine getEngine() {
JSEngine engine = pool.get();
if ( engine == null )
// Which will go into the pool when finished with.
engine = new JSEngine(scriptLib, scriptLibFile);
return engine;
}
private EnvJavaScript(String functions, String functionLibFile) {
this.scriptLib = functions;
this.scriptLibFile = functionLibFile;
}
public Object call(String functionName, Object[] args) throws NoSuchMethodException, ScriptException {
JSEngine engine = getEngine();
try {
return engine.call(functionName, args);
} finally {
pool.put(engine);
}
}
// ---- ThreadLocal version,
// private ThreadLocal<JSEngine> invocable = ThreadLocal.withInitial(()->build());
//
// private JSEngine build() {
// return new JSEngine(scriptLib, scriptLibFile);
// }
// public Object call(String functionName, Object[] args) throws NoSuchMethodException, ScriptException {
// return invocable.get().call(functionName, args);
// }
}