| /* |
| * 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.clerezza.platform.scripting; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import javax.script.Bindings; |
| import javax.script.ScriptContext; |
| import javax.script.ScriptEngine; |
| import javax.script.ScriptEngineFactory; |
| import javax.script.ScriptException; |
| import javax.ws.rs.core.MediaType; |
| import javax.ws.rs.core.Response; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.apache.clerezza.platform.content.DiscobitsHandler; |
| import org.apache.clerezza.platform.graphprovider.content.ContentGraphProvider; |
| import org.apache.clerezza.rdf.core.LiteralFactory; |
| import org.apache.clerezza.rdf.core.MGraph; |
| import org.apache.clerezza.rdf.core.NonLiteral; |
| import org.apache.clerezza.rdf.core.Resource; |
| import org.apache.clerezza.rdf.core.TypedLiteral; |
| import org.apache.clerezza.rdf.core.UriRef; |
| import org.apache.clerezza.rdf.core.access.TcManager; |
| import org.apache.clerezza.rdf.core.serializedform.Parser; |
| import org.apache.clerezza.rdf.ontologies.SCRIPT; |
| import org.apache.clerezza.rdf.utils.GraphNode; |
| |
| /** |
| * This class executes scripts, binds {@code ScriptEngineFactory}ies |
| * of installed {@code ScriptEngine}s. |
| * |
| * It provides a facade to the installed {@code ScriptEngine}s |
| * that implement {@code javax.script.ScriptEngine}. |
| * |
| * The services {@code ContentGraphProvider}, {@code DiscobitsHandler}, and |
| * {@code TcManager} are provided to the ScriptEngine's eval method through |
| * the parameter {@code Bindings}. In a script, they are accessible under the |
| * names contentGraphProvider, contentHandler, and tcManager respectively. |
| * |
| * @scr.component |
| * @scr.service |
| * interface="org.apache.clerezza.platform.scripting.ScriptExecution" |
| * @scr.reference name="scriptEngineFactory" cardinality="0..n" |
| * interface="javax.script.ScriptEngineFactory" |
| * |
| * @author hasan, daniel |
| * |
| * @see javax.script.ScriptEngineManager |
| * @see javax.script.ScriptEngine |
| */ |
| public class ScriptExecution { |
| |
| /** |
| * @scr.reference |
| */ |
| private ContentGraphProvider cgProvider; |
| |
| /** |
| * @scr.reference |
| */ |
| private DiscobitsHandler contentHandler; |
| |
| /** |
| * @scr.reference |
| */ |
| private TcManager tcManager; |
| |
| /** |
| * @scr.reference |
| */ |
| private Parser parser; |
| |
| private Map<ScriptLanguageDescription, List<ScriptEngineFactory>> |
| languageToFactoryMap = |
| new HashMap<ScriptLanguageDescription, List<ScriptEngineFactory>>(); |
| |
| private static final Logger logger = LoggerFactory.getLogger(ScriptExecution.class); |
| |
| /** |
| * @see #execute(org.apache.clerezza.rdf.core.NonLiteral, javax.script.Bindings) |
| */ |
| public Object execute(NonLiteral scriptResource) |
| throws ScriptException, NoEngineException { |
| return execute(scriptResource, null); |
| } |
| |
| /** |
| * Executes the specified {@code scriptResource}. |
| * |
| * The output is either a GraphNode or a response with |
| * the media type specified by the producedType property |
| * of the associated script. |
| * |
| * GraphNodes can be rendered by Renderlets registered for the type |
| * of the GraphNode. |
| * |
| * @param scriptResource |
| * The resource (URI). |
| * @param bindings |
| * Name/Value pairs of Java {@code Object}s made accessible |
| * to script |
| * @return |
| * The value returned from the execution of the script. |
| * Either a GraphNode or a Response. |
| * @throws ScriptException |
| * If an error occurrs in the script. |
| * @throws NoEngineException |
| * If no engine can be found |
| * |
| * @see org.apache.clerezza.rdf.ontologies.SCRIPT#Script |
| * @see org.apache.clerezza.rdf.ontologies.SCRIPT#producedType |
| * @see org.apache.clerezza.platform.typerendering.Renderlet |
| */ |
| public Object execute(NonLiteral scriptResource, Bindings bindings) |
| throws ScriptException, NoEngineException { |
| |
| MGraph contentGraph = cgProvider.getContentGraph(); |
| |
| String scriptString = null; |
| String scriptLanguage = null; |
| String scriptLanguageVersion = null; |
| String scriptProducedType = "text/plain"; |
| |
| GraphNode scriptNode = new GraphNode(scriptResource, contentGraph); |
| Iterator<Resource> it = scriptNode.getObjects(SCRIPT.scriptLanguage); |
| scriptLanguage = LiteralFactory.getInstance().createObject( |
| String.class, (TypedLiteral) it.next()); |
| |
| it = scriptNode.getObjects(SCRIPT.scriptLanguageVersion); |
| scriptLanguageVersion = LiteralFactory.getInstance().createObject( |
| String.class, (TypedLiteral) it.next()); |
| |
| it = scriptNode.getObjects(SCRIPT.producedType); |
| if(it.hasNext()) { |
| scriptProducedType = LiteralFactory.getInstance().createObject( |
| String.class, (TypedLiteral) it.next()); |
| } |
| |
| scriptString = new String( |
| contentHandler.getData((UriRef) scriptResource)); |
| |
| Object result = execute( |
| scriptString, bindings, scriptLanguage, scriptLanguageVersion); |
| if (result instanceof GraphNode) { |
| return result; |
| } |
| return Response.ok(result, MediaType.valueOf(scriptProducedType)).build(); |
| } |
| |
| /** |
| * Executes the specified {@code script} with the {@code ScriptEngine} |
| * that is registered for {@code language} and {@code languageVersion}. |
| * <p> |
| * The default {@link ScriptContext} for the {@link ScriptEngine} is used. |
| * It uses {@code bindings} as the {@link ScriptContext#ENGINE_SCOPE} |
| * Bindings of the ScriptEngine during the script execution. |
| * Three new attributes are added to the bindings: contentGraphProvider, |
| * contentHandler, and tcManager. |
| * The Reader, Writer and non-ENGINE_SCOPE Bindings of the default |
| * ScriptContext are used. The ENGINE_SCOPE Bindings of the ScriptEngine |
| * is not changed, and its mappings are unaltered by the script execution. |
| * </p> |
| * |
| * @param script |
| * The script language source to be executed. |
| * @param bindings |
| * The Bindings of attributes to be used for script execution. |
| * @param language |
| * The script language. |
| * It is used to determine the ScriptEngine. |
| * @param languageVersion |
| * The version of the script language. |
| * It is used to determine the ScriptEngine. |
| * @return |
| * The value returned from the execution of {@code script}. |
| * @throws ScriptException |
| * If an error occurrs in the script. |
| * @throws NoEngineException |
| * If no engine can be found for the specified language |
| * |
| * @see javax.script.ScriptEngine#eval(java.lang.String, javax.script.Bindings) |
| */ |
| public Object execute(String script, Bindings bindings, |
| String language, String languageVersion) |
| throws ScriptException, NoEngineException { |
| ScriptEngine engine = getScriptEngine(language, languageVersion); |
| if (engine == null) { |
| logger.warn("Cannot execute script: " + |
| "No engine available for language {}({})", |
| language, languageVersion); |
| throw new NoEngineException(new ScriptLanguageDescription(language, |
| languageVersion)); |
| } |
| if (bindings == null) { |
| bindings = engine.createBindings(); |
| } |
| addBindings(bindings); |
| return engine.eval(script, bindings); |
| } |
| |
| private void addBindings(Bindings bindings) { |
| bindings.put("contentGraphProvider", cgProvider); |
| bindings.put("contentHandler", contentHandler); |
| bindings.put("tcManager", tcManager); |
| bindings.put("parser", parser); |
| } |
| |
| private ScriptEngine getScriptEngine(String language, String languageVersion) { |
| List<ScriptEngineFactory> factoryList = null; |
| |
| try { |
| factoryList = languageToFactoryMap.get( |
| new ScriptLanguageDescription(language, languageVersion)); |
| } catch (IllegalArgumentException ex) { |
| return null; |
| } |
| |
| if (factoryList == null || factoryList.isEmpty()) { |
| return null; |
| } |
| return factoryList.get(factoryList.size() - 1).getScriptEngine(); |
| } |
| |
| /** |
| * Returns all installed script language descriptions. |
| * |
| * @return |
| * All script language descriptions |
| * of the currently installed script engines. |
| * |
| * @see ScriptLanguageDescription |
| */ |
| public Iterator<ScriptLanguageDescription> getInstalledScriptLanguages() { |
| return languageToFactoryMap.keySet().iterator(); |
| } |
| |
| /** |
| * Binds a ScriptEngineFactory. |
| * If script engine factories for the same language and/or language version |
| * already exist, they are shadowed. |
| * |
| * @param factory |
| * the script engine factory to bind |
| */ |
| protected void bindScriptEngineFactory(ScriptEngineFactory factory) { |
| String language = factory.getLanguageName(); |
| String languageVersion = factory.getLanguageVersion(); |
| |
| addScriptEngineFactory( |
| new ScriptLanguageDescription(language, languageVersion), |
| factory); |
| } |
| |
| private void addScriptEngineFactory(ScriptLanguageDescription language, |
| ScriptEngineFactory factory) { |
| |
| List<ScriptEngineFactory> factoryList = languageToFactoryMap.get(language); |
| if (factoryList == null) { |
| factoryList = new ArrayList<ScriptEngineFactory>(); |
| } else { |
| if (factoryList.contains(factory)) { |
| return; |
| } |
| } |
| factoryList.add(factory); |
| languageToFactoryMap.put(language, factoryList); |
| } |
| |
| /** |
| * Unbinds a ScriptEngineFactory. |
| * |
| * @param factory |
| * the script engine factory to unbind |
| */ |
| protected void unbindScriptEngineFactory(ScriptEngineFactory factory) { |
| String language = factory.getLanguageName(); |
| String languageVersion = factory.getLanguageVersion(); |
| |
| removeScriptEngineFactory( |
| new ScriptLanguageDescription(language, languageVersion), |
| factory); |
| } |
| |
| private void removeScriptEngineFactory(ScriptLanguageDescription language, |
| ScriptEngineFactory factory) { |
| |
| List<ScriptEngineFactory> factoryList = languageToFactoryMap.get(language); |
| if (factoryList != null) { |
| factoryList.remove(factory); |
| if (factoryList.isEmpty()) { |
| languageToFactoryMap.remove(language); |
| } |
| } |
| } |
| } |