From 825f3fa980c343cd85e67b8add68949724980feb Mon Sep 17 00:00:00 2001 From: antelder Date: Mon, 16 Nov 2009 07:58:46 +0000 Subject: Resurrect the JavaSCript client contributed in TUSCANY-417 and start getting it working with the 2.x runtime. Work in progress, but it does now work for listing/getting/invoking services in remote nodes using the tribes endpoint registry git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@880648 13f79535-47bb-0310-9956-ffa450edef68 --- .../sca/client/javascript/ScriptEngine.java | 662 +++++++++++++++++++++ .../sca/client/javascript/TuscanyShell.java | 44 ++ 2 files changed, 706 insertions(+) create mode 100644 java/sca/modules/sca-client-javascript/src/main/java/org/apache/tuscany/sca/client/javascript/ScriptEngine.java create mode 100644 java/sca/modules/sca-client-javascript/src/main/java/org/apache/tuscany/sca/client/javascript/TuscanyShell.java (limited to 'java/sca/modules/sca-client-javascript/src') diff --git a/java/sca/modules/sca-client-javascript/src/main/java/org/apache/tuscany/sca/client/javascript/ScriptEngine.java b/java/sca/modules/sca-client-javascript/src/main/java/org/apache/tuscany/sca/client/javascript/ScriptEngine.java new file mode 100644 index 0000000000..3db6a6d08c --- /dev/null +++ b/java/sca/modules/sca-client-javascript/src/main/java/org/apache/tuscany/sca/client/javascript/ScriptEngine.java @@ -0,0 +1,662 @@ +/** + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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.tuscany.sca.client.javascript; + +import java.io.BufferedReader; +import java.io.CharArrayWriter; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.client.rmi.SCAClientFactoryImpl; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.runtime.EndpointRegistry; + +import sun.org.mozilla.javascript.internal.Context; +import sun.org.mozilla.javascript.internal.Function; +import sun.org.mozilla.javascript.internal.Scriptable; +import sun.org.mozilla.javascript.internal.ScriptableObject; +import sun.org.mozilla.javascript.internal.WrappedException; +/** + * + * This class implements a Scripting Engine for the Tuscany runitme. This engine + * uses the Rhino javaScript Engine. + * + *

The default script functions supported by this engine are the following: + *

+ */ +public class ScriptEngine extends ScriptableObject implements Runnable{ + private static final long serialVersionUID = 1L; + + /** + * The context with which this script engine will be run + */ + private Context jsContext = null; + + /** + * Set of parameters passes to the script engine + */ + private String[] params = null; + + /** + * instance of Tuscany runtime + */ + private SCAClientFactoryImpl tuscany; + + /** + * A reference to the old class loader + */ + private ClassLoader oldClassLoader = null; + + /** + * Flag to indicate, if the shoutdown has requested by the user + */ + private boolean shutdown; + + /** + * The current output stream + */ + private static PrintStream out = System.out; + + /** + * The current error output stream + */ + private PrintStream err = System.err; + + /** + * The current input stream + */ + private InputStream in = System.in; + + /** + * The prompt used + */ + private String prompt = "js> "; + + /** + * The last exception that occured, used for debugging + */ + private Throwable lastException = null; + + /** + * Names of the global functions particular to the shell. Note that these functions + * are not part of ECMA. + */ + public static final String[] SCRIPT_FUNCTIONS = { + "echo", + "version", + "load", + "help", + "exit", + "printStackTrace", + "loadModule", + "listComponents", + "getComponent", + "listServices", + "getService", }; + + /** + * get the class name + * @return "global" + */ + @Override + public String getClassName() { + return "global"; + } + + /** + * Construct a script engine + * + * @param command line arguments + */ + public ScriptEngine(String[] params) { + this.params = params; + } + + /** + * Run the script engine. Invoking this method will initialize the script engine, + * Tuscany Runtime and load any SCA modules if found in the classpath. + * + */ + public void run() { + // Associate a new Context with this thread + jsContext = Context.enter(); + try { + // initialize standard objects + jsContext.initStandardObjects(this); + // define supported script functions + this.defineFunctionProperties(SCRIPT_FUNCTIONS, + ScriptEngine.class, + ScriptableObject.DONTENUM); + + // init the tuscany runtime + this.initTuscanyRuntime(); + // initialize the script engine + this.startScriptEngine(); + } + finally { + tuscany.stop(); + Thread.currentThread().setContextClassLoader(oldClassLoader); + Context.exit(); + } + } + + /** + * Print the help message. + * + * This method is defined as a script function. + */ + public void help() { + final String helpMsg = + "Command Description \n" + + "======= =========== \n" + + "help() Display this message. \n" + + "load(['f1.js', ...]) Load and execute javaScript source files named f1.js, etc. \n" + + "echo([expr ...]) Evaluate and print a variable or an expressions. \n" + + "exit() Exit this shell. \n" + + "version([number]) Get or set the javaScript version. \n" + + "printStackTrace() Print the stacktrace of the last exception \n" + + "loadModule(jar|war) Not yet implemented. \n" + + "listComponents() Not yet implemented. \n" + + "getComponent('name') Get an instance of the component with the given name. \n" + + "listServices() Not yet implemented. \n" + + "getService('name') Not yet implemented. \n"; + + out.println(); + out.println(helpMsg); + } + + /** + * Load a given module with the tuscany runtime + * + * This method is defined as a script function. + * + * @param moduleName absolute path of the module + */ + public void loadModule(final String moduleName) { + try { + File file = new File(moduleName); + URL[] urls = new URL[] {file.toURL()}; + final ClassLoader newCL = new URLClassLoader(urls); + Thread.currentThread().setContextClassLoader(newCL); + } catch (Exception e) { + err.println(e.getMessage()); + lastException = e; + } + // TODO complete this method + /* + ModuleContext context = CurrentModuleContext.getContext(); + out.println(context.toString()); + tuscany.stop(); + + try { + File file = new File(moduleName); + URL[] urls = new URL[] {file.toURL(), }; + final ClassLoader newCL = new URLClassLoader(urls); + Thread.currentThread().setContextClassLoader(newCL); + + //Class c = Class.forName("customerinfo.CustomerInfoClient", true, newCL); + //out.println("c = " + c); + + tuscany = new TuscanyRuntime(moduleName, null); + tuscany.start(); + + context = CurrentModuleContext.getContext(); + out.println(context.toString()); + + //Object component = context.locateService("CustomerInfoServiceComponent"); + //out.println(component); + } + catch (Exception e) { + err.println(e.getMessage()); + lastException = e; + } + */ + } + + /** + * List the components available within the current module + * + * This method is defined as a script function. + */ + public void listComponents() { + // TODO complete this method + } + + /** + * Get the component available within the current module with a + * given name + * + * This method is defined as a script function. + * + * @param name name of the component + * @return service component object represented by the given name + */ + public Object getComponent(String name) { +// ModuleContext tuscanyContext = CurrentModuleContext.getContext(); +// Object component = tuscanyContext.locateService(name); + +// return component; + return null; + } + + /** + * List the external services available within the current module + * + * This method is defined as a script function. + */ + public void listServices() { + EndpointRegistry epr = tuscany.getEndpointRegistry(); + for (Endpoint e : epr.getEndpoints()) { + out.println(e.getURI()); + } + } + + public Object getService(String serviceName) { + ExtensionPointRegistry extensionsRegistry = tuscany.getExtensionsRegistry(); + FactoryExtensionPoint factories = extensionsRegistry.getExtensionPoint(FactoryExtensionPoint.class); + AssemblyFactory assemblyFactory = factories.getFactory(AssemblyFactory.class); + + EndpointReference endpointReference = assemblyFactory.createEndpointReference(); + endpointReference.setReference(assemblyFactory.createComponentReference()); + Endpoint targetEndpoint = assemblyFactory.createEndpoint(); + targetEndpoint.setURI(serviceName); + endpointReference.setTargetEndpoint(targetEndpoint); + EndpointRegistry epr = tuscany.getEndpointRegistry(); + List er = epr.findEndpoint(endpointReference); + if (er.size() < 1) { + err.println("service not found " + serviceName); + return null; + } + JavaInterface ifac = ((JavaInterface)er.get(0).getInterfaceContract().getInterface()); + return getService(serviceName, ifac.getName()); + } + + /** + * Get an external service defined within the current module with a given name + * + * This method is defined as a script function. + * + * @param name name of the service + * @return service object represented by the given name + */ + protected Object getService(String serviceName, String type) { + try { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + Class serviceInterface = cl.loadClass(type); + Object service = tuscany.getService(serviceInterface, serviceName); + printService(serviceInterface); + return service; + } catch (Exception e) { + err.println(e.getClass().getSimpleName() + ": " + e.getMessage()); + lastException = e; + return null; + } + } + + private void printService(Class serviceInterface) { + out.println(serviceInterface.getName()); + for (Method m : serviceInterface.getMethods()) { + out.print(" " + m.getReturnType().getName() + " " + m.getName() + "("); + boolean one = false; + for (Class arg : m.getParameterTypes()) { + if (one) { + out.print(", "); + } + out.print(arg.getName()); + one = true; + } + out.println(")"); + } + } + + /** + * Echo a variable or a message. + * + * This method is defined as a script function. + * + * @param jsContext + * @param thisObj + * @param args + * @param function + */ + public static void echo(Context jsContext, Scriptable thisObj, Object[] args, Function function) + { + if (args.length > 0) { + out.println(args[0]); + for (int i=1; i < args.length; i++) { + out.print(" " + Context.toString(args[i])); + } + } + out.println(); + } + + /** + * print the stacktrace of the last exception + * + * This method is defined as a script function. + */ + public void printStackTrace() { + if (lastException == null) { + out.println("No stacktrace available"); + } + else { + err.println(getStackTrace(lastException)); + } + } + + /** + * Exit the shell when it is in the interactive mode. + * + * This method is defined as a script function. + */ + public void exit(){ + shutdown = true; + } + + /** + * Get and set the language version. + * + * This method is defined as a JavaScript function. + * + * @param jsContext + * @param thisObj + * @param args + * @param function + */ + public static double version(Context jsContext, Scriptable thisObj, Object[] args, Function function) + { + if (args.length > 0) { + int i = (int)Context.toNumber(args[0]); + jsContext.setLanguageVersion(i); + } + return (double) jsContext.getLanguageVersion(); + } + + /** + * Load and execute a set of JavaScript source files. + * + * This method is defined as a JavaScript function. + * + * @param jsContext + * @param thisObj + * @param args + * @param function + */ + public static void load(Context jsContext, Scriptable thisObj, Object[] args, Function function) + { + ScriptEngine engine = (ScriptEngine)getTopLevelScope(thisObj); + for (int i = 0; i < args.length; i++) { + engine.processFile(Context.toString(args[i])); + } + } + + /** + * Get the current output stream + * + * @return current output stream + */ + public PrintStream getOut() { + return out; + } + + /** + * Set the current output stream + * @param out the new output stream + */ + public void setOut(PrintStream out) { + ScriptEngine.out = out; + } + + /** + * Get the current error output stream + * + * @return Returns the current error output stream. + */ + public PrintStream getErr() { + return err; + } + + /** + * Set the current error output stream + * @param err The new error output stream to set. + */ + public void setErr(PrintStream err) { + this.err = err; + } + + /** + * Get the current input stream + * + * @return Returns the current input stream. + */ + public InputStream getIn() { + return in; + } + + /** + * Set the current input stream + * @param in The new input stream to set. + */ + public void setIn(InputStream in) { + this.in = in; + } + + /** + * initialize the Tuscany runtime + * + */ + protected void initTuscanyRuntime() { + + // Required to allow the SDO runtime to use the correct classloader + oldClassLoader = Thread.currentThread().getContextClassLoader(); +// Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + + tuscany = new SCAClientFactoryImpl(URI.create("tribes:foo")); + +// // Obtain and start the Tuscany runtime +// try { +// tuscany = new TuscanyRuntime("TuscanyClient", null); +// tuscany.start(); +// +// // this will get the module name; either specified by user or from the classpath +// String moduleName = getCurrentModuleName(); +// // TODO how do we get all the components, services exposed by this module ? +// +// } +// catch (ConfigurationException ce) { +// err.println("Failed to start Tuscany runtime: " + ce.getMessage()); +// //ce.printStackTrace(err); +// lastException = ce; +// } + } + + + /** + * start the script engine + * + */ + protected void startScriptEngine() { + + out.println("Tuscany SCA Shell 0.1, type help() for a list of supported functions."); + + // set up "arguments" in the global scope + if (params.length > 1) { + int length = params.length - 1; + Object obj[] = new Object[length]; + System.arraycopy(params, 1, obj, 0, length); + + Scriptable argsObj = jsContext.newArray(this, obj); + this.defineProperty("arguments", argsObj, ScriptableObject.DONTENUM); + } + + if (params.length == 0) { + // no file name specified, go to interactive mode + this.startInteractiveMode(); + } + else { + // TODO this could be a jar file or a script file + // process the specified file + this.processFile(params[0]); + } + System.gc(); + } + + + + /** + * Evaluate JavaScript source in the interactive mode. + * + */ + private void startInteractiveMode() + { + // see if org.mozilla.javascript.tools.shell.Main.processSource() can handle this + //Main.setErr(this.getErr()); + //Main.setOut(this.getOut()); + //Main.setIn(this.getIn()); + //Main.processSource(jsContext, filename); + + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + int currentLine = 1; + boolean done = false; + while (!shutdown && !done) { + out.print(prompt); + out.flush(); + int lineToCompile = currentLine; + try { + StringBuffer source = new StringBuffer(); + // read the next line entered by user + boolean compilable = false; + while(!compilable) { + String nextLine = reader.readLine(); + if (nextLine != null) { + currentLine += 1; + source.append(nextLine).append("\n"); + compilable = jsContext.stringIsCompilableUnit(source.toString()); + } + else { + // TODO check if this can handle Ctrl+C + System.out.println("=== Ctrl+C pressed =="); + // break both the loops + done = true; + compilable = true; + } + } + Object result = jsContext.evaluateString(this, source.toString(), "", lineToCompile, null); + if (result != Context.getUndefinedValue()) { + out.println(Context.toString(result)); + } + } + catch (Exception e) { + if (e instanceof WrappedException) { + WrappedException we = (WrappedException)e; + err.println(we.getWrappedException().getMessage()); + } + err.println(e.getMessage()); + //e.printStackTrace(err); + lastException = e; + } + } + out.println(); + } + + /** + * Read the contents from a script file and execute it. + * + * @param filename the name of the file to compile + */ + private void processFile(String fileName) { + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(fileName)); + jsContext.evaluateReader(this, reader, fileName, 1, null); + } + catch (Exception e) { + if (e instanceof WrappedException) { + WrappedException we = (WrappedException)e; + err.println(we.getWrappedException().getMessage()); + } + err.println(e.getLocalizedMessage()); + //e.printStackTrace(err); + lastException = e; + } + finally { + try { + reader.close(); + } + catch (IOException ioe) { + err.println(ioe.getLocalizedMessage()); + //ioe.printStackTrace(err); + lastException = ioe; + } + } + } + + /** + * Find the SCA module name. If the user have specified one, use that, + * otherwise, if there is a module definition in the path, pick it up. + * + * @return name of the module + */ + private String getCurrentModuleName() { + String moduleName = ""; + + // TODO parse the arguments to see if there is an SCA module name + return moduleName; + } + + /** + * Get the stacktrace for a give exception + * + * @param t Throwable from which the stacktrace need to be obtained + * @return char array containing the stack trace + */ + private char[] getStackTrace(Throwable t) { + CharArrayWriter charWriter = new CharArrayWriter(2048); + PrintWriter writer = new PrintWriter(charWriter); + t.printStackTrace(writer); + + return charWriter.toCharArray(); + } +} diff --git a/java/sca/modules/sca-client-javascript/src/main/java/org/apache/tuscany/sca/client/javascript/TuscanyShell.java b/java/sca/modules/sca-client-javascript/src/main/java/org/apache/tuscany/sca/client/javascript/TuscanyShell.java new file mode 100644 index 0000000000..abdbb2c677 --- /dev/null +++ b/java/sca/modules/sca-client-javascript/src/main/java/org/apache/tuscany/sca/client/javascript/TuscanyShell.java @@ -0,0 +1,44 @@ +/** + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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.tuscany.sca.client.javascript; + +/** + * + * This class provides a scripting shell that can be used as a Tuscany client. This shell + * extends from the Rhino JavaScript Engine's shell and provides capablities for working + * with the Tuscany Runtime. + * + *

This shell initializt the Tuscany Engine, using the input parameters that point to + * an SCA jar or war or a directory with an sca.module file. The Shell will load that module + * and then all the components and external services in the sca.module become available in the + * Shell, so that you can invoke them dynamically + * + */ +public class TuscanyShell { + + /** + * Main entry point into the shell. This method invokes the + * ScriptEngine. + * + */ + public static void main(String args[]) { + ScriptEngine engine = new ScriptEngine(args); + new Thread(engine).start(); + } + +} -- cgit v1.2.3