From 132aa8a77685ec92bc90c03f987650d275a7b639 Mon Sep 17 00:00:00 2001 From: lresende Date: Mon, 30 Sep 2013 06:59:11 +0000 Subject: 2.0.1 RC1 release tag git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1527464 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/tuscany/sca/shell/Command.java | 30 + .../java/org/apache/tuscany/sca/shell/Shell.java | 874 +++++++++++++++++++++ .../tuscany/sca/shell/commands/AddComposite.java | 92 +++ .../apache/tuscany/sca/shell/commands/Invoke.java | 142 ++++ .../apache/tuscany/sca/shell/commands/Start.java | 85 ++ .../apache/tuscany/sca/shell/commands/Stop.java | 78 ++ .../tuscany/sca/shell/commands/Uninstall.java | 68 ++ .../sca/shell/jline/CompositeURICompletor.java | 76 ++ .../tuscany/sca/shell/jline/ICURICompletor.java | 49 ++ .../tuscany/sca/shell/jline/InstallCompletor.java | 123 +++ .../org/apache/tuscany/sca/shell/jline/JLine.java | 80 ++ .../sca/shell/jline/RemoteNodeCompletor.java | 51 ++ .../tuscany/sca/shell/jline/ServiceCompletor.java | 57 ++ .../sca/shell/jline/ServiceOperationCompletor.java | 89 +++ .../tuscany/sca/shell/jline/TShellCompletor.java | 181 +++++ 15 files changed, 2075 insertions(+) create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Command.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/AddComposite.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Invoke.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Start.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Stop.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Uninstall.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/CompositeURICompletor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ICURICompletor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/InstallCompletor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/JLine.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/RemoteNodeCompletor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ServiceCompletor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ServiceOperationCompletor.java create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/TShellCompletor.java (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache') diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Command.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Command.java new file mode 100644 index 0000000000..30e46cb0e1 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Command.java @@ -0,0 +1,30 @@ +/* + * 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.tuscany.sca.shell; + +import jline.Completor; + +public interface Command { + String getName(); + String getShortHelp(); + String getHelp(); + Completor[] getCompletors(); + boolean invoke(String[] args) throws Exception; +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java new file mode 100644 index 0000000000..c1231cf13a --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java @@ -0,0 +1,874 @@ +/* + * 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.tuscany.sca.shell; + +import static java.lang.System.in; +import static java.lang.System.out; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; + +import org.apache.tuscany.sca.Node; +import org.apache.tuscany.sca.TuscanyRuntime; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.xml.Utils; +import org.apache.tuscany.sca.common.java.io.IOHelper; +import org.apache.tuscany.sca.contribution.Artifact; +import org.apache.tuscany.sca.contribution.Contribution; +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.extensibility.ServiceDeclaration; +import org.apache.tuscany.sca.extensibility.ServiceDiscovery; +import org.apache.tuscany.sca.impl.NodeImpl; +import org.apache.tuscany.sca.monitor.ValidationException; +import org.apache.tuscany.sca.runtime.ActivationException; +import org.apache.tuscany.sca.runtime.ContributionDescription; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.Version; +import org.apache.tuscany.sca.shell.jline.JLine; + +/** + * A little SCA command shell. + */ +public class Shell { + + private boolean useJline; + final List history = new ArrayList(); + private TuscanyRuntime runtime; + private String currentDomain = ""; + private Map standaloneNodes = new HashMap(); + private Map nodes = new HashMap(); + private Map commands = new HashMap(); + + public static final String[] COMMANDS = new String[] {"bye", "domain", "domains", "domainComposite", "help", "install", "installed", + "load", "nodes", "remove", "run", "save", "services", "started"}; + + public static void main(final String[] args) throws Exception { + boolean useJline = true; + String domainURI = "uri:default"; + + boolean showHelp = false; + String contribution = null; + String nodeXML = null; + for (String s : args) { + if ("-nojline".equals(s)) { + useJline = false; + } else if ("-help".equals(s)) { + showHelp = true; + } else if (s.startsWith("-nodeXML:")) { + nodeXML = s.substring("-nodeXML:".length()); + } else { + if (s.startsWith("uri:") || s.startsWith("properties:")) { + domainURI = s; + } else { + contribution = s; + } + } + } + Shell shell; + if (nodeXML != null) { + shell = new Shell(new File(nodeXML), useJline); + } else { + shell = new Shell(domainURI, useJline); + if (showHelp || contribution==null) { + shell.help(null); + } + if (contribution != null) { + System.out.println(); + System.out.println("install " + contribution + " -start"); + String curi = shell.getNode().installContribution(contribution); + shell.getNode().startDeployables(curi); + } + } + + shell.run(); + } + + public Shell(File nodeXML, boolean useJLine) throws ContributionReadException, MalformedURLException, ActivationException, ValidationException { + this.runtime = TuscanyRuntime.newInstance(); + this.useJline = useJLine; + + try { + initCommands(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + Node node = runtime.createNodeFromXML(nodeXML.toURI().toURL().toString()); + currentDomain = node.getDomainName(); + nodes.put(currentDomain, node); + } + + public Shell(String domainURI, boolean useJLine) { + this.runtime = TuscanyRuntime.newInstance(); + this.useJline = useJLine; + + try { + initCommands(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + if (domainURI != null) { + domain(domainURI); + } + } + + void initCommands() throws IOException { + for (ServiceDeclaration sd : ServiceDiscovery.getInstance().getServiceDeclarations(Command.class)) { + try { + Class c = Class.forName(sd.getClassName()); + try { + Command command = (Command)c.getConstructor(Shell.class).newInstance(this); + commands.put(command.getName(), command); + } catch (NoSuchMethodException e) { + Command command = (Command)c.newInstance(); + commands.put(command.getName(), command); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + boolean domain(final String domainURI) { + if (domainURI.length() < 1) { + currentDomain = ""; + } else { + for (Node node : nodes.values()) { + if (domainURI.equals(node.getDomainName())) { + currentDomain = node.getDomainName(); + return true; + } + } + Node node = runtime.createNode(domainURI); + currentDomain = node.getDomainName(); + nodes.put(currentDomain, node); + } + return true; + } + + boolean domains() { + for (Node node : nodes.values()) { + System.out.println(node.getDomainName()); + } + return true; + } + + boolean domainComposite() { + Composite domainComposite = getNode().getDomainComposite(); + System.out.println(Utils.modelToXML(domainComposite, true, runtime.getExtensionPointRegistry())); + return true; + } + + boolean install(final List toks) throws ContributionReadException, ActivationException, ValidationException { + if (getNode() == null) { + out.println("not in domain, use domain command first"); + return true; + } + String metaDataURL = null; + if (toks.contains("-metadata")) { + metaDataURL = toks.get(toks.indexOf("-metadata") + 1); + } + List duris = null; + if (toks.contains("-duris")) { + duris = Arrays.asList(toks.get(toks.indexOf("-duris") + 1).split(",")); + } + + String first = null; + String second = null; + for (int i = 1; i < toks.size(); i++) { + if (toks.get(i).startsWith("-")) { + if (!toks.get(i).equals("-start")) { + i++; + } + } else { + if (first == null) { + first = toks.get(i); + } else { + second = toks.get(i); + break; + } + } + } + + String curi = null; + String curl = null; + if (second != null) { + curi = first; + curl = second; + } else { + curl = first; + } + + curl = mavenProject(curl); + + String uri = getNode().installContribution(curi, curl, metaDataURL, duris); + out.println("installed at: " + uri); + return true; + } + + /** + * Try to simplify pointing at a Maven project contribution without needing target/classes suffix + */ + private String mavenProject(String curl) { + File f = new File(curl); + if (!f.exists()) { + return curl; + } + f = new File(f, "target"); + if (!f.exists()) { + return curl; + } + f = new File(f, "classes"); + if (f.exists()) { + return f.toURI().toString(); + } + // TODO: look for .zip or .jar in target? + return curl; + } + + boolean installed(final List toks) throws ContributionReadException, ValidationException { + if (getNode() == null) { + return true; + } + if (toks.size() > 1) { + String curi = toks.get(1); + ContributionDescription cd = getNode().getInstalledContribution(toks.get(1)); + if (cd == null) { + out.println("Contribution " + curi + " not installed"); + } else { + out.println(curi); + out.println(" URL: " + cd.getURL()); + + List ims = new ArrayList(); + for (String im : cd.getJavaImports()) { + ims.add(im); + } + for (String im : cd.getNamespaceImports()) { + ims.add(im); + } + out.println(" Imports: " + ims); + + List es = new ArrayList(); + for (String e : cd.getJavaExports()) { + es.add(e); + } + for (String e : cd.getNamespaceExports()) { + es.add(e); + } + out.println(" Exports: " + es); + + List ds = new ArrayList(); + for (String cp : cd.getDeployables()) { + ds.add(cp); + } + for (String cp : cd.getAdditionalDeployables().keySet()) { + ds.add(cp); + } + out.println(" Deployables: " + ds); + } + } else { + for (String curi : getNode().getInstalledContributionURIs()) { + out.println(" " + curi); + } + } + return true; + } + + boolean listComposites(final String curi) throws ContributionReadException, ValidationException { + if (getNode() == null) { + return true; + } + Contribution c = getNode().getContribution(curi); + for (Artifact a : c.getArtifacts()) { + if (a.getModel() instanceof Composite) { + out.println(((Composite)a.getModel()).getName()); + } + } + return true; + } + + boolean load(final String configXmlUrl) throws ContributionReadException, ActivationException, ValidationException { + Node node = runtime.createNodeFromXML(configXmlUrl); + currentDomain = node.getDomainName(); + nodes.put(currentDomain, node); + return true; + } + + boolean run(final String commandsFileURL) throws IOException { + BufferedReader r = new BufferedReader(new InputStreamReader(IOHelper.getLocationAsURL(commandsFileURL).openStream())); + String l; + try { + while ((l = r.readLine()) != null) { + out.println(l); + String[] toks = l != null ? l.trim().split(" ") : "".split(" "); + List toksList = getTokens(toks); + apply(eval(toksList)); + } + } finally { + r.close(); + } + return true; + } + + boolean save(final String directory) throws IOException { + out.println("TODO: not yet implemented"); + return true; + } + + boolean services() throws IOException { + if (getNode() == null) { + return true; + } + DomainRegistry reg = ((NodeImpl)getNode()).getEndpointRegistry(); + for (Endpoint endpoint : reg.getEndpoints()) { + out.println(endpoint.getComponent().getURI() + "/" + endpoint.getService().getName()); + for (Binding b : endpoint.getService().getBindings()) { + if (!SCABinding.TYPE.equals(b.getType())) { + out.println(" " + b.getType().getLocalPart() + " " + b.getURI()); + } + } + } + return true; + } + + public boolean bye() { + for (Node node : nodes.values()) { + node.stop(); + } + runtime.stop(); + for (Node node : standaloneNodes.values()) { + node.stop(); + } + return false; + } + + boolean started(final List toks) { + if (standaloneNodes.size() > 0) { + out.println("Standalone Nodes:"); + for (String nodeName : standaloneNodes.keySet()) { + Node node = standaloneNodes.get(nodeName); + Map> scs = node.getStartedCompositeURIs(); + for (String curi : scs.keySet()) { + for (String dc : scs.get(curi)) { + out.println(" " + nodeName + " " + dc); + } + } + } + out.println(); + } + if (nodes.size() > 0) { + for (Node node : nodes.values()) { + out.println("Domain: " + node.getDomainName()); +// List ics; +// if (toks.size() > 1) { +// ics = new ArrayList(); +// ics.add(toks.get(1)); +// } else { +// ics = node.getInstalledContributionURIs(); +// } +// +// for (String curi : ics) { +// List cs = node.getStartedCompositeURIs().get(curi); +// if (cs != null) { + for (String curi : node.getStartedCompositeURIs().keySet()) { + for (String compositeURI : node.getStartedCompositeURIs().get(curi)) { + + String runningNodeName = node.getRunningNodeName(curi, compositeURI); + if (node.getLocalNodeName().equals(runningNodeName)) { + runningNodeName = "this"; + } + if ("LocalOnly".equals(runningNodeName)) { + runningNodeName = ""; + } else { + runningNodeName = " (" + runningNodeName + ")"; + } + + out.println(" " + curi + " " + compositeURI + runningNodeName); + } + } +// } +// } + } + } + return true; + } + + boolean nodes() { + String localNode = getNode().getLocalNodeName(); + for (String node : getNode().getNodeNames()) { + out.println(node + (localNode.equals(node) ? " (this)" : "")); + } + return true; + } + + boolean status() { + return true; + } + + boolean history() { + for (String l : history) + out.println(l); + return true; + } + + public String[] getCommandNames() { + List cmds = new ArrayList(); + cmds.addAll(commands.keySet()); + cmds.addAll(Arrays.asList(COMMANDS)); + return cmds.toArray(new String[]{}); + } + + public Map getCommands() { + return commands; + } + + public Node getNode() { + return nodes.get(currentDomain); + } + + List read(Object r) throws IOException { + out.println(); + out.print(currentDomain + "> "); + final String l; + if (useJline) { + l = JLine.readLine(r); + } else { + l = ((BufferedReader)r).readLine(); + history.add(l); + } + + String[] toks = l != null ? l.trim().split(" ") : "bye".split(" "); + return getTokens(toks); + } + + /** + * Parse the string into tokens, which may include quoted strings + */ + List getTokens(String[] toks) { + List toksList = new ArrayList(); + for (int i=0; i 0) { + int j = quotedString(toks, i); + if (j > -1) { + StringBuilder sb = new StringBuilder(); + sb.append(toks[i]); + for (int k=i+1; k<=j; k++) { + sb.append(" "); + sb.append(toks[k]); + } + i = j; + String s = sb.toString(); + toksList.add(s.substring(1, s.length()-1)); + } else { + toksList.add(toks[i]); + } + } + } + return toksList; + } + + int quotedString(String[] toks, int i) { + if (toks[i].startsWith("\"") || toks[i].startsWith("'")) { + for (int j=i+1; j eval(final List toks) { + final String op = toks.size() > 0 ? toks.get(0) : ""; + + if (commands.keySet().contains(op)) { + toks.remove(0); + return new Callable() { + public Boolean call() throws Exception { + return commands.get(op).invoke(toks.toArray(new String[0])); + } + }; + } + if (op.equalsIgnoreCase("domain")) + return new Callable() { + public Boolean call() throws Exception { + return domain(toks.size() > 1 ? toks.get(1) : ""); + } + }; + if (op.equalsIgnoreCase("domains")) + return new Callable() { + public Boolean call() throws Exception { + return domains(); + } + }; + if (op.equalsIgnoreCase("domainComposite")) + return new Callable() { + public Boolean call() throws Exception { + return domainComposite(); + } + }; + if (op.equalsIgnoreCase("install")) + return new Callable() { + public Boolean call() throws Exception { + return install(toks); + } + }; + if (op.equalsIgnoreCase("installed")) + return new Callable() { + public Boolean call() throws Exception { + return installed(toks); + } + }; + if (op.equalsIgnoreCase("load")) + return new Callable() { + public Boolean call() throws Exception { + return load(toks.get(1)); + } + }; + if (op.equalsIgnoreCase("nodes")) + return new Callable() { + public Boolean call() throws Exception { + return nodes(); + } + }; + if (op.equalsIgnoreCase("run")) + return new Callable() { + public Boolean call() throws Exception { + return run(toks.get(1)); + } + }; + if (op.equalsIgnoreCase("help")) + return new Callable() { + public Boolean call() { + return help(toks); + } + }; + if (op.equalsIgnoreCase("save")) + return new Callable() { + public Boolean call() throws Exception { + return save(toks.get(1)); + } + }; + if (op.equalsIgnoreCase("services")) + return new Callable() { + public Boolean call() throws Exception { + return services(); + } + }; + if (op.equalsIgnoreCase("bye")) + return new Callable() { + public Boolean call() throws Exception { + return bye(); + } + }; + if (op.equalsIgnoreCase("started")) + return new Callable() { + public Boolean call() { + return started(toks); + } + }; + if (op.equalsIgnoreCase("status")) + return new Callable() { + public Boolean call() { + return status(); + } + }; + if (op.equalsIgnoreCase("history")) + return new Callable() { + public Boolean call() { + return history(); + } + }; + if (op.equalsIgnoreCase("") || op.startsWith("#")) + return new Callable() { + public Boolean call() { + return true; + } + }; + return new Callable() { + public Boolean call() { + out.println("unknown command"); + return true; + } + }; + } + + boolean apply(final Callable func) { + try { + return func.call(); + } catch (Exception e) { + e.printStackTrace(); + return true; + } + } + + public void run() throws IOException { + Object reader; + if (useJline) { + reader = JLine.createJLineReader(this); + } else { + reader = new BufferedReader(new InputStreamReader(in)); + } + while (apply(eval(read(reader)))) + ; + } + + boolean help(List toks) { + String command = (toks == null || toks.size() < 2) ? null : toks.get(1); + if (command == null) { + helpOverview(); + } else if (commands.keySet().contains(command)) { + out.println(commands.get(command).getShortHelp()); + out.println(); + out.println(commands.get(command).getHelp()); + } else if ("help".equalsIgnoreCase(command)) { + helpHelp(); + } else if ("install".equalsIgnoreCase(command)) { + helpInstall(); + } else if ("installed".equalsIgnoreCase(command)) { + helpInstalled(); + } else if ("load".equalsIgnoreCase(command)) { + helpLoad(); + } else if ("run".equalsIgnoreCase(command)) { + helpRun(); + } else if ("save".equalsIgnoreCase(command)) { + helpSave(); + } else if ("started".equalsIgnoreCase(command)) { + helpStarted(); + } else if ("startup".equalsIgnoreCase(command)) { + helpStartUp(); + } else if ("status".equalsIgnoreCase(command)) { + helpStatus(); + } else if ("services".equalsIgnoreCase(command)) { + helpServices(); + } else if ("bye".equalsIgnoreCase(command)) { + helpBye(); + } + return true; + } + + boolean helpOverview() { + out.println("Apache Tuscany Shell (" + Version.getVersion() + ")"); + out.println("Commands:"); + out.println(); + out.println(" help"); + + for (Command command : commands.values()) { + out.println(" " + command.getShortHelp()); + } + + out.println(" domain "); + out.println(" domains"); + out.println(" install [] [-metadata ] [-duris ]"); + out.println(" installed []"); + out.println(" nodes"); + out.println(" run "); + out.println(" save "); + out.println(" services"); + out.println(" started"); + out.println(" status"); + out.println(" bye"); + out.println(); + if (useJline) + out.println("Use Tab key for command and argument completion"); + out.println("For detailed help on each command do 'help ', for help of startup options do 'help startup'"); + return true; + } + + void helpHelp() { + out.println(" help []"); + out.println(); + out.println(" Outputs help on the Tuscany Shell"); + out.println(" If the command argument is used it provides detailed help on that command otherwise"); + out.println(" it provides an overview of available Shell commands"); + out.println(); + out.println(" To get help on starting the Tuscany Shell use 'help startup'"); + out.println(); + out.println(" Arguments:"); + out.println(" - (optional) the command to get detailed help on"); + } + + void helpDomain() { + out.println(" domain []"); + out.println(); + out.println(" Starts or connects to a domain for the given domain URI."); + out.println(" If no domain URI is specified switch to standalone mode."); + out.println(); + out.println(" Arguments:"); + out.println(" - (optional) the domain URI of the domain"); + } + + void helpDomains() { + out.println(" domains"); + out.println(); + out.println(" Shows the currently defined domain URIs"); + out.println(); + out.println(" Arguments:"); + out.println(" none"); + } + + void helpInstall() { + out.println(" install [] [-start] [-metadata ] [-duris ]"); + out.println(); + out.println(" Creates an installed contribution with a supplied root contribution, installed at abase URI."); + out.println(); + out.println(" Arguments:"); + out.println(" uri - (optional) the URI (name) to use for the contribution. When no uri is specified"); + out.println(" a default URI is used derived from the contribution URL"); + out.println(" contributionURL - (required) the URL to the contribution to install"); + out.println(" -start - (optional) start any composites listed as deployable in the sca-contribution.xml file"); + out.println(" -metadata - (optional) the URL to an external contribution meta data document that should be"); + out.println(" merged into any existing sca-contributions.xml file within the contribution."); + out.println(" -duris - (optional) specifies the URIs of contributions that are used to resolve the"); + out.println(" dependencies of the root contribution and other dependent contributions."); + out.println(" When not specified all installed contributions are used to resolve dependencies."); + } + + void helpInstalled() { + out.println(" installed []"); + out.println(); + out.println(" Shows information about the contributions installed on this node,"); + out.println(" including the contribution URI and location along with the URI"); + out.println(" and QName of any composites within the contribution"); + out.println(); + out.println(" Arguments:"); + out.println(" contributionURI - (optional) the URI of an installed contribution"); + } + + void helpLoad() { + out.println(" load "); + out.println(); + out.println(" Shows information about the contributions installed on this node,"); + out.println(" including the contribution URI and location along with the URI"); + out.println(" and QName of any composites within the contribution"); + out.println(); + out.println(" Arguments:"); + out.println(" configXmlUrl - (required) the URL of the config file to load"); + } + + void helpRemove() { + out.println(" remove "); + out.println(); + out.println(" Removes an installed contribution"); + out.println(); + out.println(" Arguments:"); + out.println(" contributionURI - (required) the URI of an installed contribution"); + } + + void helpRun() { + out.println(" run "); + out.println(); + out.println(" Runs shell commands stored in file."); + out.println(" The file should be a text file with one shell command per line. Blank lines and "); + out.println(" lines starting with # will be ignored."); + out.println(); + out.println(" Arguments:"); + out.println(" commandsFileURL - (required) the URL of the commands file to run"); + } + + void helpSave() { + out.println(" save "); + out.println(); + out.println(" Saves the current Node state to directory."); + out.println(" This will include a node-config.xml file and copies of all artifacts"); + out.println(" being used by the Node."); + out.println(); + out.println(" Arguments:"); + out.println(" directoryPath - (required) the URL of a directory to be used to store the state."); + } + + void helpServices() { + out.println(" services"); + out.println(); + out.println(" Lists the components and services available in the Domain."); + out.println(); + out.println(" Arguments:"); + out.println(" none"); + } + + void helpStarted() { + out.println(" started [ []]"); + out.println(); + out.println(" Shows the status of the Node, listing for each started composite, its"); + out.println(" contribution URI, the composite URI, and the composite QName."); + out.println(); + out.println(" Arguments:"); + out.println(" curi - (optional) the URI of an installed contribution"); + out.println(" compositeUri - (optional) the URI of a composite"); + } + + void helpStatus() { + out.println(" status"); + out.println(); + out.println(" Shows the status of the Shell including information on the known domains,"); + out.println(" installed contributions, and started composites"); + out.println(); + out.println(" Arguments:"); + out.println(" none"); + } + + void helpBye() { + out.println(" bye"); + out.println(); + out.println(" All deployed composites are stopped and the Shell exists."); + out.println(); + out.println(" Arguments:"); + out.println(" none"); + } + + void helpStartUp() { + out.println(" Tuscany Shell StartUp Options "); + out.println(); + out.println(" When starting the Tuscany Shell there are optional arguments that can configure the Shell."); + out.println(); + out.println(" Arguments:"); + out.println(" (optional) the URI of the domain."); + out.println(" When the domainURI is a simple string then the Shell starts a standalone"); + out.println(" Node using the string as the domain name or 'default' if no name is specified."); + out.println(" When the domainURI starts with 'uri:' the Shell starts a distributed Node "); + out.println(" and the URI can encode parameters to configure the domain as follows:"); + out.println(" uri: "; + } + + @Override + public String getHelp() { + StringBuilder helpText = new StringBuilder(); + helpText.append("Adds a deployable composite to an installed contribution.\n"); + helpText.append("\n"); + helpText.append("Arguments:\n"); + helpText.append(" contributionURI - (required) the URI of the installed contribution\n"); + helpText.append(" compositeURL - (required) the URL to an external composite file\n"); + return helpText.toString(); + } + + @Override + public Completor[] getCompletors() { + return new Completor[]{new ICURICompletor(shell), new FileNameCompletor(), new NullCompletor()}; + } + + @Override + public boolean invoke(String[] args) throws ContributionReadException, FileNotFoundException, XMLStreamException, ActivationException, ValidationException, URISyntaxException { + if (args.length != 2) { + System.err.println("Wrong number of args"); + System.err.println(getShortHelp()); + return true; + } + if (!!!shell.getNode().getInstalledContributionURIs().contains(args[0])) { + System.err.println("contribution not installed: " + args[0]); + return true; + } + + File f = new File(IOHelper.getLocationAsURL(args[1]).toURI()); + shell.getNode().addDeploymentComposite(args[0], new FileReader(f)); + return true; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Invoke.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Invoke.java new file mode 100644 index 0000000000..fe93903bce --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Invoke.java @@ -0,0 +1,142 @@ +/* + * 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.tuscany.sca.shell.commands; + +import static java.lang.System.out; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; + +import jline.Completor; +import jline.NullCompletor; + +import org.apache.tuscany.sca.shell.Command; +import org.apache.tuscany.sca.shell.Shell; +import org.apache.tuscany.sca.shell.jline.ServiceCompletor; +import org.apache.tuscany.sca.shell.jline.ServiceOperationCompletor; + +public class Invoke implements Command { + + private Shell shell; + + public Invoke(Shell shell) { + this.shell = shell; + } + + @Override + public String getName() { + return "invoke"; + } + + @Override + public String getShortHelp() { + return "invoke [/] [ ...]"; + } + + @Override + public String getHelp() { + StringBuilder helpText = new StringBuilder(); + helpText.append(" Invokes an operation of a component service.\n"); + helpText.append(" (presently parameters are limited to simple types)\n"); + helpText.append("\n"); + helpText.append(" Arguments:\n"); + helpText.append(" component - (required) the name of the component\n"); + helpText.append(" service - (optional) the name of the component service, which may be omitted\n"); + helpText.append(" when the component has a single service.\n"); + helpText.append(" operation - (required) the name of the operation\n"); + helpText.append(" args - (optional) the operation arguments\n"); + return helpText.toString(); + } + + @Override + public Completor[] getCompletors() { + return new Completor[]{new ServiceCompletor(shell), new ServiceOperationCompletor(shell), new NullCompletor()}; + } + + @Override + public boolean invoke(String[] args) throws Exception { + if (args.length < 2) { + System.err.println("Wrong number of args"); + System.err.println(getShortHelp()); + return true; + } + String endpointName = args[0]; + String operationName = args[1]; + String params[] = new String[args.length - 2]; + System.arraycopy(args, 2, params, 0, params.length); + Object proxy = shell.getNode().getService(null, endpointName); + invoke(proxy, operationName, params); + return true; + } + + static void invoke(Object proxy, String operationName, String... params) throws IllegalAccessException, InvocationTargetException { + Method foundMethod = null; + for (Method m : proxy.getClass().getMethods()) { + if (m.getName().equals(operationName)) { + if (m.getParameterTypes().length == params.length) { + Object parameters[] = new Object[params.length]; + int i = 0; + for (Class type : m.getParameterTypes()) { + if (type == byte.class || type == Byte.class) { + parameters[i] = Byte.valueOf(params[i]); + } else if (type == char.class || type == Character.class) { + parameters[i] = params[i].charAt(0); + } else if (type == boolean.class || type == Boolean.class) { + parameters[i] = Boolean.valueOf(params[i]); + } else if (type == short.class || type == Short.class) { + parameters[i] = Short.valueOf(params[i]); + } else if (type == int.class || type == Integer.class) { + parameters[i] = Integer.valueOf(params[i]); + } else if (type == long.class || type == Long.class) { + parameters[i] = Long.valueOf(params[i]); + } else if (type == float.class || type == Float.class) { + parameters[i] = Float.valueOf(params[i]); + } else if (type == double.class || type == Double.class) { + parameters[i] = Double.valueOf(params[i]); + } else if (type == String.class) { + parameters[i] = params[i]; + } else { + throw new IllegalArgumentException("Parameter type is not supported: " + type); + } + i++; + } + Object result = m.invoke(proxy, parameters); + + if (result != null && result.getClass().isArray()) { + out.println(Arrays.toString((Object[])result)); + } else { + out.println(result); + } + + return; + + } else { + foundMethod = m; + } + } + } + if (foundMethod != null) { + System.err.println("Service operation " + foundMethod.getName() + " expects " + foundMethod.getParameterTypes().length + " arguments"); + } else { + System.err.println("Operation not found: " + operationName); + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Start.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Start.java new file mode 100644 index 0000000000..c0f354b419 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Start.java @@ -0,0 +1,85 @@ +/* + * 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.tuscany.sca.shell.commands; + +import jline.Completor; +import jline.NullCompletor; + +import org.apache.tuscany.sca.shell.Command; +import org.apache.tuscany.sca.shell.Shell; +import org.apache.tuscany.sca.shell.jline.CompositeURICompletor; +import org.apache.tuscany.sca.shell.jline.ICURICompletor; +import org.apache.tuscany.sca.shell.jline.RemoteNodeCompletor; + +public class Start implements Command { + + private Shell shell; + + public Start(Shell shell) { + this.shell = shell; + } + + @Override + public String getName() { + return "start"; + } + + @Override + public String getShortHelp() { + return "start []"; + } + + @Override + public String getHelp() { + StringBuilder helpText = new StringBuilder(); + helpText.append(" Start a composite.\n"); + helpText.append("\n"); + helpText.append(" The composite is added to the domain composite with semantics that correspond to the domain-level\n"); + helpText.append(" composite having an statement that references the supplied composite. All of the composite's\n"); + helpText.append(" components become top-level components and the component services become externally visible\n"); + helpText.append(" services (eg. they would be present in a WSDL description of the Domain).\n"); + helpText.append("\n"); + helpText.append(" Arguments:\n"); + helpText.append(" curi - (required) the URI of an installed contribution\n"); + helpText.append(" compositeUri - (required) the URI of a composite within the contribution to start\n"); + helpText.append(" remoteNode - (optional) the name of a remote node which should run the composite\n"); + return helpText.toString(); + } + + @Override + public Completor[] getCompletors() { + return new Completor[]{new ICURICompletor(shell), new CompositeURICompletor(shell), new RemoteNodeCompletor(shell), new NullCompletor()}; + } + + @Override + public boolean invoke(String[] args) throws Exception { + if (args.length == 2) { + shell.getNode().startComposite(args[0], args[1]); + } else if (args.length == 3) { + shell.getNode().startComposite(args[0], args[1], args[2]); + } else { + System.err.println("Wrong number of args"); + System.err.println(getShortHelp()); + return true; + } + return true; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Stop.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Stop.java new file mode 100644 index 0000000000..5bef2c2edb --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Stop.java @@ -0,0 +1,78 @@ +/* + * 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.tuscany.sca.shell.commands; + +import jline.Completor; +import jline.NullCompletor; + +import org.apache.tuscany.sca.shell.Command; +import org.apache.tuscany.sca.shell.Shell; +import org.apache.tuscany.sca.shell.jline.CompositeURICompletor; +import org.apache.tuscany.sca.shell.jline.ICURICompletor; + +public class Stop implements Command { + + private Shell shell; + + public Stop(Shell shell) { + this.shell = shell; + } + + @Override + public String getName() { + return "stop"; + } + + @Override + public String getShortHelp() { + return "stop "; + } + + @Override + public String getHelp() { + StringBuilder helpText = new StringBuilder(); + helpText.append(" Stop a composite.\n"); + helpText.append("\n"); + helpText.append(" The composite is removed from the domain composite, along with all the components, wires,\n"); + helpText.append(" services and references originally added when the composite was started.\n"); + helpText.append("\n"); + helpText.append(" Arguments:\n"); + helpText.append(" curi - (required) the URI of an installed contribution\n"); + helpText.append(" compositeUri - (required) the URI of a composite within the contribution to stop\n"); + return helpText.toString(); + } + + @Override + public Completor[] getCompletors() { + return new Completor[]{new ICURICompletor(shell), new CompositeURICompletor(shell), new NullCompletor()}; + } + + @Override + public boolean invoke(String[] args) throws Exception { + if (args.length != 2) { + System.err.println("Wrong number of args"); + System.err.println(getShortHelp()); + return true; + } + shell.getNode().stopComposite(args[0], args[1]); + return true; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Uninstall.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Uninstall.java new file mode 100644 index 0000000000..76f17d7651 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/commands/Uninstall.java @@ -0,0 +1,68 @@ +/* + * 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.tuscany.sca.shell.commands; + +import jline.Completor; +import jline.NullCompletor; + +import org.apache.tuscany.sca.shell.Command; +import org.apache.tuscany.sca.shell.Shell; +import org.apache.tuscany.sca.shell.jline.ICURICompletor; + +public class Uninstall implements Command { + + private Shell shell; + + public Uninstall(Shell shell) { + this.shell = shell; + } + + @Override + public String getName() { + return "uninstall"; + } + + @Override + public String getShortHelp() { + return "uninstall "; + } + + @Override + public String getHelp() { + StringBuilder helpText = new StringBuilder(); + helpText.append(" Uninstall an installed contribution"); + helpText.append("\n"); + helpText.append(" Arguments:"); + helpText.append(" contributionURI - (required) the URI of the contribution to uninstall"); + return helpText.toString(); + } + + @Override + public Completor[] getCompletors() { + return new Completor[]{new ICURICompletor(shell), new NullCompletor()}; + } + + @Override + public boolean invoke(String[] args) throws Exception { + shell.getNode().uninstallContribution(args[0]); + return true; + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/CompositeURICompletor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/CompositeURICompletor.java new file mode 100644 index 0000000000..fe40a4051a --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/CompositeURICompletor.java @@ -0,0 +1,76 @@ +/* + * 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.tuscany.sca.shell.jline; + +import java.util.ArrayList; +import java.util.List; + +import jline.SimpleCompletor; + +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.contribution.Artifact; +import org.apache.tuscany.sca.contribution.Contribution; +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.monitor.ValidationException; +import org.apache.tuscany.sca.shell.Shell; + +/** + * A Completor that uses the composite URIs within a Contribution + * Will only work if the argument before the composite URI is a contribution URI + */ +public class CompositeURICompletor extends SimpleCompletor { + + private Shell shell; + + public CompositeURICompletor(Shell shell) { + super(""); + this.shell = shell; + } + + @Override + public int complete(final String buffer, final int cursor, final List clist) { + if (shell.getNode() == null) { + return -1; + } + Contribution c; + try { + c = shell.getNode().getContribution(getContributionURI()); + } catch (Exception e) { + return super.complete(buffer, cursor, clist); + } + if (c == null) { + return -1; + } + + List cus = new ArrayList(); + for (Artifact a : c.getArtifacts()) { + if (a.getModel() instanceof Composite) { + cus.add(((Composite)a.getModel()).getURI()); + } + } + setCandidateStrings(cus.toArray(new String[cus.size()])); + return super.complete(buffer, cursor, clist); + } + + protected String getContributionURI() { + /* A little hacky to use a static but i can't see how else to get the contribution URI */ + return TShellCompletor.lastArg; + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ICURICompletor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ICURICompletor.java new file mode 100644 index 0000000000..a596725971 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ICURICompletor.java @@ -0,0 +1,49 @@ +/* + * 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.tuscany.sca.shell.jline; + +import java.util.List; + +import jline.SimpleCompletor; + +import org.apache.tuscany.sca.shell.Shell; + +/** + * An Installed Contribution URI Completor + */ +public class ICURICompletor extends SimpleCompletor { + + private Shell shell; + + public ICURICompletor(Shell shell) { + super(""); + this.shell = shell; + } + + @Override + public int complete(final String buffer, final int cursor, final List clist) { + if (shell.getNode() != null) { + List ics = shell.getNode().getInstalledContributionURIs(); + setCandidateStrings(ics.toArray(new String[ics.size()])); + } + return super.complete(buffer, cursor, clist); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/InstallCompletor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/InstallCompletor.java new file mode 100644 index 0000000000..f615fe610b --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/InstallCompletor.java @@ -0,0 +1,123 @@ +/* + * 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.tuscany.sca.shell.jline; + +import java.io.File; +import java.util.List; + +import jline.FileNameCompletor; + +import org.apache.tuscany.sca.shell.Shell; + +/** + * A Completor for the install command. + * The command format is: install [] [-start] [-metadata ] [-duris ] + * + * TODO: doesn't seem to complete the -xxx parameters properly yet + * + */ +public class InstallCompletor extends FileNameCompletor { + + ICURICompletor icuriCompletor; + + public InstallCompletor(Shell shell) { + icuriCompletor = new ICURICompletor(shell); + } + + public int complete(final String buf, final int cursor, + final List candidates) { + +// System.err.println("buf:" + buf); +// System.err.println("candidates:" + candidates); + + if ("-duris".equals(TShellCompletor.lastArg)) { + return icuriCompletor.complete(buf, cursor, candidates); + } + if ("-metadata".equals(TShellCompletor.lastArg)) { + return super.complete(buf, cursor, candidates); + } + + return super.complete(buf, cursor, candidates); + } + + @Override + public int matchFiles(String buffer, String translated, File[] entries, + List candidates) { + if (entries == null) { + return -1; + } + + int matches = 0; + + // first pass: just count the matches + for (int i = 0; i < entries.length; i++) { + if (entries[i].getAbsolutePath().startsWith(translated)) { + matches++; + } + } + if ("-metadata".startsWith(buffer)) { + matches++; + } + if ("-duris".startsWith(buffer)) { + matches++; + } + if ("-start".startsWith(buffer)) { + matches++; + } + + // green - executable + // blue - directory + // red - compressed + // cyan - symlink + for (int i = 0; i < entries.length; i++) { + if (entries[i].getAbsolutePath().startsWith(translated)) { + String name = + entries[i].getName() + + (((matches == 1) && entries[i].isDirectory()) + ? File.separator : " "); + + /* + if (entries [i].isDirectory ()) + { + name = new ANSIBuffer ().blue (name).toString (); + } + */ + candidates.add(name); + } + } + + if ("-metadata".startsWith(buffer) && !TShellCompletor.allArgs.contains("-metadata")) { + candidates.add("-metadata" + (matches == 1 ? " " : "")); + } + if ("-duris".startsWith(buffer) && !TShellCompletor.allArgs.contains("-duris")) { + candidates.add("-duris" + (matches == 1 ? " " : "")); + } + if ("-start".startsWith(buffer) && !TShellCompletor.allArgs.contains("-start")) { + candidates.add("-start" + (matches == 1 ? " " : "")); + } + + final int index = buffer.lastIndexOf(File.separator); + + int x= index + File.separator.length(); +// System.out.println("x="+x); + return x; +// return index + File.separator.length(); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/JLine.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/JLine.java new file mode 100644 index 0000000000..e8fcd627e2 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/JLine.java @@ -0,0 +1,80 @@ +/* + * 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.tuscany.sca.shell.jline; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.LinkedList; +import java.util.List; + +import jline.Completor; +import jline.ConsoleReader; + +import org.apache.tuscany.sca.shell.Shell; + +/** + * Keep all the JLine specific code out of the Shell class so that it runs ok + * when jline isn't on the classpath. + */ +public class JLine { + + public static String readLine(Object r) throws IOException { + return ((ConsoleReader)r).readLine(); + } + + public static Object createJLineReader(final Shell shell) throws IOException { + ConsoleReader reader = new ConsoleReader(); + fixCtrlC(reader); + // Add a Ctrl-c listener + reader.addTriggeredAction((char)3, new ActionListener() { + public void actionPerformed(ActionEvent e) { + shell.bye(); + System.exit(0); + } + }); + reader.setBellEnabled(false); + // TODO: write a Completor specific to this that can handle the individual command arguments + List completors = new LinkedList(); +// completors.add(new SimpleCompletor(Shell.COMMANDS)); +// completors.add(new ICURICompletor(shell.node)); +// completors.add(new FileNameCompletor()); +// reader.addCompletor(new ArgumentCompletor(completors)); + reader.addCompletor(new TShellCompletor(shell)); + return reader; + } + + /** + * The windowsbindings.properties shipped inside jline maps ctrl-c to INSERT + * with the comment "(frankly, I wasn't sure where to bind this)". That does not + * seem a great choice as it disables ctrl-c interupt so this resets that binding. + */ + private static void fixCtrlC(ConsoleReader reader) { + try { + Field f = ConsoleReader.class.getDeclaredField("keybindings"); + f.setAccessible(true); + short[] keybindings = (short[])f.get(reader); + if (keybindings[3] == -48) keybindings[3] = 3; + } catch (Exception e) { + e.printStackTrace(); // shouldnt happen + } + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/RemoteNodeCompletor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/RemoteNodeCompletor.java new file mode 100644 index 0000000000..6cc7577fee --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/RemoteNodeCompletor.java @@ -0,0 +1,51 @@ +/* + * 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.tuscany.sca.shell.jline; + +import java.util.List; + +import jline.SimpleCompletor; + +import org.apache.tuscany.sca.shell.Shell; + +/** + * A Completor for the names of the remote nodes in the domain + */ +public class RemoteNodeCompletor extends SimpleCompletor { + + private Shell shell; + + public RemoteNodeCompletor(Shell shell) { + super(""); + this.shell = shell; + } + + @Override + public int complete(final String buffer, final int cursor, final List clist) { + if (shell.getNode() == null) { + return -1; + } + + List nodes = shell.getNode().getNodeNames(); + nodes.remove(shell.getNode().getLocalNodeName()); + setCandidateStrings(nodes.toArray(new String[nodes.size()])); + return super.complete(buffer, cursor, clist); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ServiceCompletor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ServiceCompletor.java new file mode 100644 index 0000000000..4f86b1d1b3 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ServiceCompletor.java @@ -0,0 +1,57 @@ +/* + * 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.tuscany.sca.shell.jline; + +import java.util.ArrayList; +import java.util.List; + +import jline.SimpleCompletor; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.impl.NodeImpl; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.shell.Shell; + +/** + * A Completor for available services + */ +public class ServiceCompletor extends SimpleCompletor { + + private Shell shell; + + public ServiceCompletor(Shell shell) { + super(""); + this.shell = shell; + } + + @Override + public int complete(final String buffer, final int cursor, final List clist) { + if (shell.getNode() != null) { + List services = new ArrayList(); + DomainRegistry reg = ((NodeImpl)shell.getNode()).getEndpointRegistry(); + for (Endpoint endpoint : reg.getEndpoints()) { + services.add(endpoint.getComponent().getURI() + "/" + endpoint.getService().getName()); + } + setCandidateStrings(services.toArray(new String[services.size()])); + } + return super.complete(buffer, cursor, clist); + } + +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ServiceOperationCompletor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ServiceOperationCompletor.java new file mode 100644 index 0000000000..c61e8cf4ca --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ServiceOperationCompletor.java @@ -0,0 +1,89 @@ +/* + * 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.tuscany.sca.shell.jline; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import jline.SimpleCompletor; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.impl.NodeImpl; +import org.apache.tuscany.sca.runtime.DomainRegistry; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.shell.Shell; +import org.oasisopen.sca.NoSuchServiceException; + +/** + * A Completor for available service operations + */ +public class ServiceOperationCompletor extends SimpleCompletor { + + private Shell shell; + private static final List EXCLUDED_OPS = Arrays.asList(new String[] {"equals", "getClass", + "getInvocationHandler", + "getProxyClass", "hashCode", + "isProxyClass", "newProxyInstance", + "notify", "notifyAll", "toString", + "wait", "CGLIB$SET_STATIC_CALLBACKS", + "CGLIB$SET_THREAD_CALLBACKS", + "CGLIB$findMethodProxy", + "getCallback", "getCallbacks", + "newInstance", "setCallback", + "setCallbacks"}); + + public ServiceOperationCompletor(Shell shell) { + super(""); + this.shell = shell; + } + + @Override + public int complete(final String buffer, final int cursor, final List clist) { + String service = TShellCompletor.lastArg; +// DomainRegistry reg = ((NodeImpl)shell.getNode()).getEndpointRegistry(); +// List endpoints = reg.findEndpoint(service); +// if (endpoints.size() < 1) { +// return -1; +// } +// String serviceName = null; +// if (service.contains("/")) { +// int i = service.indexOf("/"); +// if (i < service.length()-1) { +// serviceName = service.substring(i+1); +// } +// } +// Object proxy = ((RuntimeComponent)endpoints.get(0).getComponent()).getServiceReference(null, serviceName).getService(); + try { + Object proxy = shell.getNode().getService(null, service); + Method[] ms = proxy.getClass().getMethods(); + List ops = new ArrayList(); + for (Method m : ms) { + if (!EXCLUDED_OPS.contains(m.getName())) { + ops.add(m.getName()); + } + } + setCandidateStrings(ops.toArray(new String[ops.size()])); + } catch (NoSuchServiceException e) { + } + return super.complete(buffer, cursor, clist); + } +} diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/TShellCompletor.java b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/TShellCompletor.java new file mode 100644 index 0000000000..3f38caf1e5 --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/TShellCompletor.java @@ -0,0 +1,181 @@ +/* + * 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.tuscany.sca.shell.jline; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import jline.ArgumentCompletor; +import jline.Completor; +import jline.ConsoleReader; +import jline.FileNameCompletor; +import jline.NullCompletor; +import jline.SimpleCompletor; + +import org.apache.tuscany.sca.shell.Command; +import org.apache.tuscany.sca.shell.Shell; + +/** + * A Completor thats specific to the Tuscany Shell that knows about + * each command and has an argument specific Completor for each command argument. + */ +public class TShellCompletor extends ArgumentCompletor { + + Map completors; + final Completor commandCompletor; + final ArgumentDelimiter delim = new WhitespaceArgumentDelimiter(); + final Shell shell; + + static String lastArg; + static List allArgs; + + public TShellCompletor(Shell shell) { + super((Completor)null); + this.shell = shell; + this.commandCompletor = new SimpleCompletor(shell.getCommandNames()); + + completors = new HashMap(); + completors.put("help", new Completor[]{commandCompletor, commandCompletor, new NullCompletor()}); + completors.put("install", new Completor[]{commandCompletor, new InstallCompletor(shell)}); + completors.put("installed", new Completor[]{commandCompletor, new ICURICompletor(shell), new NullCompletor()}); + completors.put("invoke", new Completor[]{commandCompletor, new ServiceCompletor(shell), new ServiceOperationCompletor(shell), new NullCompletor()}); + completors.put("load", new Completor[]{commandCompletor, new FileNameCompletor(), new NullCompletor()}); + completors.put("remove", new Completor[]{commandCompletor, new ICURICompletor(shell), new NullCompletor()}); + completors.put("run", new Completor[]{commandCompletor, new FileNameCompletor(), new NullCompletor()}); + completors.put("save", new Completor[]{commandCompletor, new FileNameCompletor(), new NullCompletor()}); + completors.put("start", new Completor[]{commandCompletor, new ICURICompletor(shell), new CompositeURICompletor(shell), new RemoteNodeCompletor(shell), new NullCompletor()}); + completors.put("started", new Completor[]{commandCompletor, new ICURICompletor(shell), new CompositeURICompletor(shell), new NullCompletor()}); + completors.put("stop", new Completor[]{commandCompletor, new ICURICompletor(shell), new CompositeURICompletor(shell), new NullCompletor()}); + + for (Command c : shell.getCommands().values()) { + List compleors = new ArrayList(); + compleors.add(commandCompletor); + compleors.addAll(Arrays.asList(c.getCompletors())); + completors.put(c.getName(), compleors.toArray(new Completor[]{})); + } + } + + @Override + /** + * Copied from JLine ArgumentCompletor class. The only change is to + * get the completors by using the getCompletors method and setting the lastArg static. + */ + public int complete(final String buffer, final int cursor, + final List candidates) { + + ArgumentList list = delim.delimit(buffer, cursor); + int argpos = list.getArgumentPosition(); + int argIndex = list.getCursorArgumentIndex(); + + if (argIndex < 0) { + return -1; + } + + if (argIndex > 0) { + /* set the last argument in a static for the CompositeURICompletor */ + lastArg = list.getArguments()[argIndex-1]; + if (lastArg != null) lastArg = lastArg.trim(); + } + allArgs = Arrays.asList(list.getArguments()); + + final Completor comp; + + Completor[] completors = getCompletors(buffer); + + // if we are beyond the end of the completors, just use the last one + if (argIndex >= completors.length) { + comp = completors[completors.length - 1]; + } else { + comp = completors[argIndex]; + } + + // ensure that all the previous completors are successful before + // allowing this completor to pass (only if strict is true). + for (int i = 0; getStrict() && (i < argIndex); i++) { + Completor sub = + completors[(i >= completors.length) ? (completors.length - 1) : i]; + String[] args = list.getArguments(); + String arg = ((args == null) || (i >= args.length)) ? "" : args[i]; + + List subCandidates = new LinkedList(); + + if (sub.complete(arg, arg.length(), subCandidates) == -1) { + return -1; + } + + if (subCandidates.size() == 0) { + return -1; + } + } + + int ret = comp.complete(list.getCursorArgument(), argpos, candidates); + + if (ret == -1) { + return -1; + } + + int pos = ret + (list.getBufferPosition() - argpos); + + /** + * Special case: when completing in the middle of a line, and the + * area under the cursor is a delimiter, then trim any delimiters + * from the candidates, since we do not need to have an extra + * delimiter. + * + * E.g., if we have a completion for "foo", and we + * enter "f bar" into the buffer, and move to after the "f" + * and hit TAB, we want "foo bar" instead of "foo bar". + */ + if ((cursor != buffer.length()) && delim.isDelimiter(buffer, cursor)) { + for (int i = 0; i < candidates.size(); i++) { + String val = candidates.get(i).toString(); + + while ((val.length() > 0) + && delim.isDelimiter(val, val.length() - 1)) { + val = val.substring(0, val.length() - 1); + } + + candidates.set(i, val); + } + } + + ConsoleReader.debug("Completing " + buffer + "(pos=" + cursor + ") " + + "with: " + candidates + ": offset=" + pos); + + return pos; + } + + protected Completor[] getCompletors(String buffer) { + StringBuilder sb = new StringBuilder(); + for (int i=0; i