diff options
Diffstat (limited to '')
8 files changed, 1329 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0-Beta1/modules/shell/META-INF/MANIFEST.MF b/sca-java-2.x/branches/2.0-Beta1/modules/shell/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..0d49e4c715 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta1/modules/shell/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0
+SCA-Version: 1.1
+Export-Package: org.apache.tuscany.sca.shell;version="2.0.0"
+Bundle-Name: Apache Tuscany SCA Shell
+Bundle-Vendor: The Apache Software Foundation
+Bundle-Version: 2.0.0
+Bundle-ManifestVersion: 2
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Description: Apache Tuscany SCA Domain Node
+Import-Package:
+ org.apache.tuscany.sca.management;version="2.0.0",
+ org.apache.tuscany.sca.node;version="2.0.0",
+ org.apache.tuscany.sca.node2;version="2.0.0",
+ org.apache.tuscany.sca.node.configuration;version="2.0.0",
+ org.apache.tuscany.sca.node.impl;version="2.0.0",
+ org.apache.tuscany.sca.runtime;version="2.0.0",
+ org.apache.tuscany.sca.context;version="2.0.0",
+ org.apache.tuscany.sca.work;version="2.0.0"
+Bundle-SymbolicName: org.apache.tuscany.sca.domain.node
+Bundle-DocURL: http://www.apache.org/
+Bundle-RequiredExecutionEnvironment: J2SE-1.5,JavaSE-1.6
diff --git a/sca-java-2.x/branches/2.0-Beta1/modules/shell/pom.xml b/sca-java-2.x/branches/2.0-Beta1/modules/shell/pom.xml new file mode 100644 index 0000000000..66ac7aaeb5 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta1/modules/shell/pom.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<project>
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-modules</artifactId>
+ <version>2.0-Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>tuscany-shell</artifactId>
+ <name>Apache Tuscany SCA Shell</name>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-domain-node</artifactId>
+ <version>2.0-Beta1-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>jline</groupId>
+ <artifactId>jline</artifactId>
+ <version>0.9.94</version>
+ <optional>true</optional>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java b/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java new file mode 100644 index 0000000000..d0cfc25e88 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java @@ -0,0 +1,768 @@ +/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+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.assembly.Composite;
+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.monitor.ValidationException;
+import org.apache.tuscany.sca.node2.Node;
+import org.apache.tuscany.sca.node2.NodeFactory;
+import org.apache.tuscany.sca.runtime.ActivationException;
+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<String> history = new ArrayList<String>();
+ private NodeFactory factory;
+ private String currentDomain = "";
+ private Map<String, Node> standaloneNodes = new HashMap<String, Node>();
+ private Map<String, Node> nodes = new HashMap<String, Node>();
+
+ public static final String[] COMMANDS = new String[] {"bye", "domain", "domains", "help", "install", "installed",
+ "load", "remove", "run", "save", "start", "status",
+ "stop"};
+
+ public static void main(final String[] args) throws Exception {
+ boolean useJline = true;
+ String domainURI = "default";
+ for (String s : args) {
+ if ("-nojline".equals(s)) {
+ useJline = false;
+ } else {
+ domainURI = s;
+ }
+ }
+ new Shell(domainURI, useJline).run();
+ }
+
+ public Shell(String domainURI, boolean useJLine) {
+ this.factory = NodeFactory.newInstance();
+ this.useJline = useJLine;
+ if (domainURI != null) {
+ domain(domainURI);
+ }
+ }
+
+ 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 = factory.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 install(final List<String> toks) throws ContributionReadException, ActivationException, ValidationException {
+ if (getNode() == null) {
+ out.println("not in domain, use domain command first");
+ return true;
+ }
+ boolean startDeployables = toks.contains("-start");
+ String metaDataURL = null;
+ if (toks.contains("-metadata")) {
+ metaDataURL = toks.get(toks.indexOf("-metadata") + 1);
+ }
+ List<String> 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;
+ }
+
+ String uri = getNode().installContribution(curi, curl, metaDataURL, duris, startDeployables);
+ out.println("installed at: " + uri);
+ return true;
+ }
+
+ boolean installed(final List<String> toks) {
+ List<String> curis;
+ if (toks.size() > 1) {
+ curis = Arrays.asList(new String[] {toks.get(1)});
+ } else {
+ if (getNode() == null) {
+ return true;
+ }
+ curis = getNode().getInstalledContributions();
+ }
+ for (String curi : curis) {
+ out.println(curi + " " + getNode().getInstalledContribution(curi).getLocation());
+ Contribution c = getNode().getInstalledContribution(curi);
+ List<String> deployeds = getNode().getDeployedComposites(curi);
+ for (Artifact a : c.getArtifacts()) {
+ if (a.getModel() instanceof Composite) {
+ Composite composite = (Composite)a.getModel();
+ String running = deployeds.contains(composite.getURI()) ? "***running***" : "";
+ out.println(" " + composite.getURI() + " " + composite.getName() + " " + running);
+ }
+ }
+ }
+ return true;
+ }
+
+ boolean listComposites(final String curi) {
+ if (getNode() == null) {
+ return true;
+ }
+ Contribution c = getNode().getInstalledContribution(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 = factory.createNodeFromXML(configXmlUrl);
+ currentDomain = node.getDomainName();
+ nodes.put(currentDomain, node);
+ return true;
+ }
+
+ boolean remove(final String curi) throws ContributionReadException, ActivationException, ValidationException {
+ if (getNode() == null) {
+ out.println("not in domain, use domain command first");
+ return true;
+ }
+ getNode().removeContribution(curi);
+ 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<String> toksList = new ArrayList<String>();
+ for (String s : toks) {
+ if (s != null && s.trim().length() > 0) {
+ toksList.add(s);
+ }
+ }
+ apply(eval(toksList));
+ }
+ } finally {
+ r.close();
+ }
+ return true;
+ }
+
+ boolean save(final String directory) throws IOException {
+ out.println("TODO: not yet implemented");
+ return true;
+ }
+
+ public boolean stop(List<String> toks) throws ActivationException {
+ String curi = toks.get(1);
+ if (toks.size() > 2) {
+ getNode().removeFromDomainLevelComposite(curi, toks.get(2));
+ } else {
+ if (standaloneNodes.containsKey(curi)) {
+ standaloneNodes.remove(curi).stop();
+ } else if (nodes.containsKey(curi)) {
+ Node n = nodes.remove(curi);
+ n.stop();
+ if (n.getDomainName().equals(currentDomain)) {
+ currentDomain = "";
+ }
+ } else {
+ for (String compositeURI : getNode().getDeployedComposites(curi)) {
+ getNode().removeFromDomainLevelComposite(curi, compositeURI);
+ }
+ }
+ }
+ return true;
+ }
+
+ public boolean bye() {
+ for (Node node : nodes.values()) {
+ node.stop();
+ }
+ factory.stop();
+ for (Node node : standaloneNodes.values()) {
+ node.stop();
+ }
+ return false;
+ }
+
+ boolean start(String curi, String compositeURI) throws ActivationException, ValidationException {
+ Contribution c = getNode().getInstalledContribution(curi);
+ for (Artifact a : c.getArtifacts()) {
+ if (compositeURI.equals(a.getURI())) {
+ getNode().addToDomainLevelComposite(curi, compositeURI);
+ return true;
+ }
+ }
+ // external composite file ('composite by value')
+ try {
+ URL url = IOHelper.getLocationAsURL(compositeURI);
+ InputStream is = IOHelper.openStream(url);
+ BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ getNode().addDeploymentComposite(curi, br);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ return true;
+ }
+
+ boolean start(String nodeName, String compositeURI, String contributionURL, String... dependentContributionURLs)
+ throws ActivationException, ValidationException {
+ Node node = NodeFactory.newStandaloneNode(compositeURI, contributionURL, dependentContributionURLs);
+ standaloneNodes.put(nodeName, node);
+ return true;
+ }
+
+ boolean status(final List<String> toks) {
+ if (standaloneNodes.size() > 0) {
+ out.println("Standalone Nodes:");
+ for (String nodeName : standaloneNodes.keySet()) {
+ Node node = standaloneNodes.get(nodeName);
+ for (String curi : node.getInstalledContributions()) {
+ for (String dc : node.getDeployedComposites(curi)) {
+ out.println(" " + nodeName + " " + dc);
+ }
+ }
+ }
+ out.println();
+ }
+ if (nodes.size() > 0) {
+ for (Node node : nodes.values()) {
+ out.println("Domain: " + node.getDomainName());
+ List<String> ics;
+ if (toks.size() > 1) {
+ ics = new ArrayList<String>();
+ ics.add(toks.get(1));
+ } else {
+ ics = node.getInstalledContributions();
+ }
+
+ for (String curi : ics) {
+ Contribution c = node.getInstalledContribution(curi);
+ List<String> dcs = node.getDeployedComposites(curi);
+ if (toks.size() > 2) {
+ dcs = new ArrayList<String>();
+ dcs.add(toks.get(2));
+ } else {
+ dcs = node.getDeployedComposites(curi);
+ }
+ for (String compositeUri : dcs) {
+ for (Artifact a : c.getArtifacts()) {
+ if (compositeUri.equals(a.getURI())) {
+ out.println(" " + curi
+ + " "
+ + compositeUri
+ + " "
+ + ((Composite)a.getModel()).getName());
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ boolean history() {
+ for (String l : history)
+ out.println(l);
+ return true;
+ }
+
+ public Node getNode() {
+ return nodes.get(currentDomain);
+ }
+
+ List<String> read(Object r) throws IOException {
+ 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(" ");
+ List<String> toksList = new ArrayList<String>();
+ for (String s : toks) {
+ if (s != null && s.trim().length() > 0) {
+ toksList.add(s);
+ }
+ }
+ return toksList;
+ }
+
+ Callable<Boolean> eval(final List<String> toks) {
+ final String op = toks.size() > 0 ? toks.get(0) : "";
+
+ if (op.equalsIgnoreCase("domain"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return domain(toks.size() > 1 ? toks.get(1) : "");
+ }
+ };
+ if (op.equalsIgnoreCase("domains"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return domains();
+ }
+ };
+ if (op.equalsIgnoreCase("install"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return install(toks);
+ }
+ };
+ if (op.equalsIgnoreCase("installed"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return installed(toks);
+ }
+ };
+ if (op.equalsIgnoreCase("load"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return load(toks.get(1));
+ }
+ };
+ if (op.equalsIgnoreCase("remove"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return remove(toks.get(1));
+ }
+ };
+ if (op.equalsIgnoreCase("run"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return run(toks.get(1));
+ }
+ };
+ if (op.equalsIgnoreCase("help"))
+ return new Callable<Boolean>() {
+ public Boolean call() {
+ return help(toks);
+ }
+ };
+ if (op.equalsIgnoreCase("save"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return save(toks.get(1));
+ }
+ };
+ if (op.equalsIgnoreCase("stop"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return stop(toks);
+ }
+ };
+ if (op.equalsIgnoreCase("bye"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ return bye();
+ }
+ };
+ if (op.equalsIgnoreCase("start"))
+ return new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ if (currentDomain.length() > 0) {
+ return start(toks.get(1), toks.get(2));
+ } else {
+ String[] duris = null;
+ if (toks.contains("-duris")) {
+ int i = toks.indexOf("-duris");
+ duris = toks.get(i + 1).split(",");
+ toks.remove(i); toks.remove(i+1);
+ }
+ String name = toks.get(1);
+ String contributionURL;
+ String compositeURI;
+ if (toks.size() > 3) {
+ compositeURI = toks.get(2);
+ contributionURL = toks.get(3);
+ } else {
+ compositeURI = null;
+ contributionURL = toks.get(2);
+ }
+ return start(name, compositeURI, contributionURL, duris);
+ }
+ }
+ };
+ if (op.equalsIgnoreCase("status"))
+ return new Callable<Boolean>() {
+ public Boolean call() {
+ return status(toks);
+ }
+ };
+ if (op.equalsIgnoreCase("history"))
+ return new Callable<Boolean>() {
+ public Boolean call() {
+ return history();
+ }
+ };
+ if (op.equalsIgnoreCase("") || op.startsWith("#"))
+ return new Callable<Boolean>() {
+ public Boolean call() {
+ return true;
+ }
+ };
+ return new Callable<Boolean>() {
+ public Boolean call() {
+ out.println("unknown command");
+ return true;
+ }
+ };
+ }
+
+ boolean apply(final Callable<Boolean> func) {
+ try {
+ return func.call();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return true;
+ }
+ }
+
+ public void run() throws IOException {
+ help(null);
+ Object reader;
+ if (useJline) {
+ reader = JLine.createJLineReader(this);
+ } else {
+ reader = new BufferedReader(new InputStreamReader(in));
+ }
+ while (apply(eval(read(reader))))
+ ;
+ }
+
+ boolean help(List<String> toks) {
+ String command = (toks == null || toks.size() < 2) ? null : toks.get(1);
+ if (command == null) {
+ helpOverview();
+ } 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 ("remove".equalsIgnoreCase(command)) {
+ helpRemove();
+ } else if ("run".equalsIgnoreCase(command)) {
+ helpRun();
+ } else if ("save".equalsIgnoreCase(command)) {
+ helpSave();
+ } else if ("start".equalsIgnoreCase(command)) {
+ helpStart();
+ } else if ("status".equalsIgnoreCase(command)) {
+ helpStatus();
+ } else if ("stop".equalsIgnoreCase(command)) {
+ helpStop();
+ } else if ("startup".equalsIgnoreCase(command)) {
+ helpStartUp();
+ } else if ("bye".equalsIgnoreCase(command)) {
+ helpBye();
+ }
+ return true;
+ }
+
+ boolean helpOverview() {
+ out.println("Apache Tuscany Shell (" + Version.getVersion()
+ + " "
+ + Version.getRevsion()
+ + " "
+ + Version.getBuildTime()
+ + ")");
+ out.println("Commands:");
+ out.println();
+ out.println(" help");
+ out.println(" domain <domainURI>");
+ out.println(" domains");
+ out.println(" install [<uri>] <contributionURL> [-start] [-metadata <url>] [-duris <uri,uri,...>]");
+ out.println(" installed [<contributionURI>]");
+ out.println(" load <configXmlURL>");
+ out.println(" remove <contributionURI>");
+ out.println(" run <commandsFileURL>");
+ out.println(" save <directoryPath>");
+ out.println(" start <curi> <compositeUri>|<contentURL>");
+ out.println(" start <name> [<compositeUri>] <contributionURL> [-duris <uri,uri,...>]");
+ out.println(" status [<curi> [<compositeUri>]]");
+ out.println(" stop [<curi> [<compositeUri>]]");
+ 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 <command>', for help of startup options do 'help startup'");
+ out.println();
+ return true;
+ }
+
+ void helpHelp() {
+ out.println(" help [<command>]");
+ 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(" <command> - (optional) the command to get detailed help on");
+ }
+
+ void helpDomain() {
+ out.println(" domain [<domainURI>]");
+ 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(" <domainURI> - (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 [<uri>] <contributionURL> [-start] [-metadata <url>] [-duris <uri,uri,...>]");
+ 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 <url> - (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 <uri,uri,...> - (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 [<contributionURI>]");
+ 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 <configXmlUrl>");
+ 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 <contributionURI>");
+ 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 <commandsFileURL>");
+ 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 <directoryPath>");
+ 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 helpStart() {
+ out.println(" start <curi> <compositeUri>|<contentURL>");
+ out.println(" start <name> [<compositeUri>] <contributionURL> [-duris <uri,uri,...>]");
+ out.println();
+ out.println(" Starts a composite.");
+ out.println(" The composite is added to the domain composite with semantics that correspond to the domain-level");
+ out.println(" composite having an <include> statement that references the supplied composite. All of the composites");
+ out.println(" components become top-level components and the component services become externally visible");
+ out.println(" services (eg. they would be present in a WSDL description of the Domain).");
+ out.println();
+ out.println(" The second form of the start command starts in standalone mode not part of any SCA domain.");
+ out.println();
+ out.println(" Arguments (form1):");
+ out.println(" curi - (required) the URI of an installed contribution");
+ out.println(" compositeUri or contentURL - (required) either the URI of a composite within the contribution");
+ out.println(" or a URL to an external composite file.");
+ out.println(" Arguments (form2):");
+ out.println(" name - (required) a name for the started composite/contribution");
+ out.println(" compositeUri - (optional) the URI of a composite within the contribution");
+ out.println(" contributionURL - (required) the URL to the contribution");
+ out.println(" -duris <uri,uri,...> - (optional) specifies the URIs of contributions that are used to resolve the");
+ out.println(" dependencies of the root contribution and other dependent contributions.");
+ }
+
+ void helpStatus() {
+ out.println(" status [<curi> [<compositeUri>]]");
+ out.println();
+ out.println(" Shows the status of the Node, listing for each deployed 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 helpStop() {
+ out.println(" stop [<curi> [<compositeUri>]]");
+ out.println(" stop <name>");
+ out.println();
+ out.println(" Stops a domain or standalone node or individual composites and contributions in a Domain.");
+ out.println(" If a composite URI is specified then the composite is removed from the Domain Level composite");
+ out.println(" This means that the removal of the components, wires, services and references originally added");
+ out.println(" to the domain level composite by the identified composite. If a contribution URI is specified");
+ out.println(" without a composite URI then all deployed composites composites in the contribution are stopped.");
+ out.println();
+ out.println(" Arguments:");
+ out.println(" curi - (required) the URI of an installed contribution");
+ out.println(" compositeUri - (optional) the URI of a composite");
+ out.println(" name - (required) the name of a standalon node or domain to stop");
+ }
+
+ 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(" <domainURI> (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:<domainName?key1=value1&key2=value2&...");
+ out.println(" The keys are optional and some keys are:");
+ out.println(" bind=ip[:port] - defines the local bind address and port, if the port is not specified it");
+ out.println(" defaults 14820 and if that port in use it will try incrementing by one till a free port is found.");
+ out.println(" multicast=groupip:port | off - defines if multicast discovery is used and if so what multicast IP group and port is used.");
+ out.println(" It defaults to 224.5.12.10:51482. A value of 'off' means multicast is disabled.");
+ out.println(" wka=ip[:port] - a comma separated list of ip address and port for remote nodes in");
+ out.println(" the domain group when multicast is not available. The port defaults to 14820.");
+ out.println(" userid= is the userid other nodes must use to connect to this domain group. The default is the default domain name.");
+ out.println(" password= is the password other nodes must use to connect to this domain group. The default is 'tuscany'.");
+ out.println();
+ out.println(" -nojline (optional) use plain Java System.in/out instead of JLine");
+ out.println(" (no tab completion or advanced line editing will be available)");
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/CompositeURICompletor.java b/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/CompositeURICompletor.java new file mode 100644 index 0000000000..c07c3acaee --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/CompositeURICompletor.java @@ -0,0 +1,69 @@ +/* + * 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.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 = shell.getNode().getInstalledContribution(getContributionURI()); + if (c == null) { + return -1; + } + + List<String> cus = new ArrayList<String>(); + 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/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ICURICompletor.java b/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/ICURICompletor.java new file mode 100644 index 0000000000..b197bc9b37 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta1/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<String> ics = shell.getNode().getInstalledContributions(); + setCandidateStrings(ics.toArray(new String[ics.size()])); + } + return super.complete(buffer, cursor, clist); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/InstallCompletor.java b/sca-java-2.x/branches/2.0-Beta1/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/branches/2.0-Beta1/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 [<uri>] <contributionURL> [-start] [-metadata <url>] [-duris <uri,uri,...>] + * + * 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/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/JLine.java b/sca-java-2.x/branches/2.0-Beta1/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/branches/2.0-Beta1/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<Completor> completors = new LinkedList<Completor>(); +// 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/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/TShellCompletor.java b/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/TShellCompletor.java new file mode 100644 index 0000000000..83d292a555 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta1/modules/shell/src/main/java/org/apache/tuscany/sca/shell/jline/TShellCompletor.java @@ -0,0 +1,169 @@ +/* + * 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.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.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<String, Completor[]> completors; + final Completor commandCompletor = new SimpleCompletor(Shell.COMMANDS); + final ArgumentDelimiter delim = new WhitespaceArgumentDelimiter(); + final Shell shell; + + static String lastArg; + static List<String> allArgs; + + public TShellCompletor(Shell shell) { + super((Completor)null); + this.shell = shell; + completors = new HashMap<String, Completor[]>(); + 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("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 NullCompletor()}); + completors.put("status", 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()}); + } + + @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<buffer.length(); i++) { + if (Character.isWhitespace(buffer.charAt(i))) { + break; + } + sb.append(buffer.charAt(i)); + } + String command = sb.toString(); + Completor[] comps = completors.get(command); + return comps == null ? new Completor[]{commandCompletor} : comps; + } +} |