/******************************************************************************* * Copyright (c) 2007-2008 Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Cambridge Semantics Incorporated *******************************************************************************/ package org.openanzo.execution.javascript; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import org.mozillax.javascript.Context; import org.mozillax.javascript.ContextFactory; import org.mozillax.javascript.Function; import org.mozillax.javascript.Scriptable; import org.openanzo.client.AnzoClient; import org.openanzo.exceptions.AnzoException; import org.openanzo.exceptions.ExceptionConstants; import org.openanzo.exceptions.LogUtils; import org.openanzo.execution.BaseServiceExecutor; import org.openanzo.execution.IExecutionContext; import org.openanzo.ontologies.execution.JavascriptSemanticService; import org.openanzo.ontologies.execution.SemanticService; import org.openanzo.ontologies.execution.SemanticServiceFactory; import org.openanzo.osgi.registry.RegistryDataset; import org.openanzo.rdf.Constants; import org.openanzo.rdf.IDataset; import org.openanzo.rdf.URI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The JavaScript Semantic Service Executor * * @author Ben Szekely ( <a href="mailto:ben@cambridgesemantics.com">ben@cambridgesemantics.com </a>) * */ class JavascriptServiceExecutor extends BaseServiceExecutor { private static final Logger log = LoggerFactory.getLogger(JavascriptServiceExecutor.class); Map<URI, JavascriptService> services = new HashMap<URI, JavascriptService>(); @Override public boolean initializeService(SemanticService service, AnzoClient anzoClient) throws AnzoException { JavascriptSemanticService javascriptService = SemanticServiceFactory.getJavascriptSemanticService(service.resource(), service.graph()); String resource = javascriptService.getScriptResource(); InputStream in = getClass().getResourceAsStream(resource); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(in, Constants.byteEncoding)); StringBuilder script = new StringBuilder(); String line = reader.readLine(); while (line != null) { script.append("\r\n").append(line); line = reader.readLine(); } Context cx = ContextFactory.getGlobal().enterContext(); try { Scriptable scope = cx.initStandardObjects(); cx.evaluateString(scope, script.toString(), service.uri(), 1, null); setupJavascriptObjects(scope); Object serviceObj = scope.get("service", scope); if (serviceObj == Scriptable.NOT_FOUND) { throw new AnzoException(ExceptionConstants.EXECUTION.SERVICE_INITIALIZATION_ERROR, "Could not find service object in Javascript service"); } Scriptable serviceObject = (Scriptable) serviceObj; Object initObj = serviceObject.get("initialize", serviceObject); if (!(initObj instanceof Function)) { throw new AnzoException(ExceptionConstants.EXECUTION.SERVICE_INITIALIZATION_ERROR, "Service object does not contain initialize method"); } Object stopObj = serviceObject.get("stop", serviceObject); if (!(stopObj instanceof Function)) { throw new AnzoException(ExceptionConstants.EXECUTION.SERVICE_INITIALIZATION_ERROR, "Service object does not contain stop method"); } Function initializeFunction = (Function) initObj; initializeFunction.call(cx, scope, scope, new Object[] { service, anzoClient }); JavascriptService serviceInfo = new JavascriptService(); serviceInfo.serviceScript = script.toString(); serviceInfo.serviceScope = scope; services.put((URI) service.resource(), serviceInfo); } finally { Context.exit(); } return true; } catch (IOException e) { throw new AnzoException(ExceptionConstants.EXECUTION.SERVICE_INITIALIZATION_ERROR, e); } catch (Throwable e) { log.error(LogUtils.EXECUTION_MARKER, "Javascript Error:", e); return false; } finally { try { if (reader != null) reader.close(); in.close(); } catch (IOException e) { throw new AnzoException(ExceptionConstants.EXECUTION.SERVICE_INITIALIZATION_ERROR, e); } } } @Override public void executeService(URI serviceUri, URI operationUri, IExecutionContext ec, IDataset request, IDataset response) throws AnzoException { JavascriptService serviceInfo = services.get(serviceUri); String operation = operationUri.getLocalName(); Context cx = ContextFactory.getGlobal().enterContext(); try { Scriptable scope = cx.newObject(serviceInfo.serviceScope); scope.setPrototype(serviceInfo.serviceScope); scope.setParentScope(null); cx.evaluateString(scope, serviceInfo.serviceScript, serviceUri.toString(), 1, null); Scriptable serviceObject = (Scriptable) scope.get("service", scope); Object funcObj = serviceObject.get(operation, serviceObject); if (!(funcObj instanceof Function)) { throw new AnzoException(ExceptionConstants.EXECUTION.SERVICE_INITIALIZATION_ERROR, "Unknown operation: " + operation); } Function function = (Function) funcObj; Object[] args = new Object[] { ec, request, response }; function.call(cx, scope, scope, args); } finally { Context.exit(); } } @Override public void registryReset(RegistryDataset registry) throws AnzoException { // shouldn't have to do anything here. } @Override public void stopService(URI serviceUri, AnzoClient anzoClient) throws AnzoException { JavascriptService serviceInfo = services.get(serviceUri); Context cx = ContextFactory.getGlobal().enterContext(); try { Scriptable scope = cx.newObject(serviceInfo.serviceScope); scope.setPrototype(serviceInfo.serviceScope); scope.setParentScope(null); cx.evaluateString(scope, serviceInfo.serviceScript, serviceUri.toString(), 1, null); Object serviceObj = scope.get("service", scope); Scriptable serviceObject = (Scriptable) serviceObj; Object stopObj = serviceObject.get("stop", serviceObject); Function stopFunction = (Function) stopObj; stopFunction.call(cx, scope, scope, null); } finally { Context.exit(); } } @Override public void verifyOperation(URI serviceUri, URI operationUri) throws AnzoException { JavascriptService serviceInfo = services.get(serviceUri); Context cx = ContextFactory.getGlobal().enterContext(); try { Scriptable scope = cx.newObject(serviceInfo.serviceScope); scope.setPrototype(serviceInfo.serviceScope); scope.setParentScope(null); cx.evaluateString(scope, serviceInfo.serviceScript, serviceUri.toString(), 1, null); Scriptable serviceObject = (Scriptable) scope.get("service", scope); String op = operationUri.getLocalName(); Object funcObj = serviceObject.get(op, serviceObject); if (!(funcObj instanceof Function)) { throw new AnzoException(ExceptionConstants.EXECUTION.SERVICE_INITIALIZATION_ERROR, "Unknown operation: " + op); } } finally { Context.exit(); } } private void setupJavascriptObjects(Scriptable scope) { scope.put("valueFactory", scope, Constants.valueFactory); scope.put("log", scope, log); } public URI getServiceTypeUri() { return JavascriptSemanticService.TYPE; } public URI getServiceUri(URI operationUri, IDataset request) throws AnzoException { return null; } private static class JavascriptService { Scriptable serviceScope; String serviceScript; } }