diff options
3 files changed, 183 insertions, 29 deletions
diff --git a/sca-java-2.x/trunk/modules/shell/pom.xml b/sca-java-2.x/trunk/modules/shell/pom.xml index fe896d05ae..e13b74325d 100644 --- a/sca-java-2.x/trunk/modules/shell/pom.xml +++ b/sca-java-2.x/trunk/modules/shell/pom.xml @@ -38,6 +38,13 @@ <version>2.0-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/trunk/modules/shell/src/main/java/org/apache/tuscany/sca/shell/JLine.java b/sca-java-2.x/trunk/modules/shell/src/main/java/org/apache/tuscany/sca/shell/JLine.java new file mode 100644 index 0000000000..88a0e7ca51 --- /dev/null +++ b/sca-java-2.x/trunk/modules/shell/src/main/java/org/apache/tuscany/sca/shell/JLine.java @@ -0,0 +1,79 @@ +/* + * 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 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.ArgumentCompletor; +import jline.Completor; +import jline.ConsoleReader; +import jline.FileNameCompletor; +import jline.SimpleCompletor; + +/** + * 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.stop(); + 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 FileNameCompletor()); + reader.addCompletor(new ArgumentCompletor(completors)); + 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/trunk/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java b/sca-java-2.x/trunk/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java index dda2e441af..0cffabbe07 100644 --- a/sca-java-2.x/trunk/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java +++ b/sca-java-2.x/trunk/modules/shell/src/main/java/org/apache/tuscany/sca/shell/Shell.java @@ -25,8 +25,10 @@ import static java.lang.System.out; import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -34,6 +36,10 @@ import java.util.concurrent.Callable; import javax.xml.stream.XMLStreamException;
+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;
@@ -41,27 +47,31 @@ import org.apache.tuscany.sca.node2.NodeFactory; import org.apache.tuscany.sca.runtime.ActivationException;
import org.apache.tuscany.sca.runtime.Version;
-
/**
* A little SCA command shell.
*/
public class Shell {
- final NodeFactory nodeFactory = NodeFactory.newInstance();
Node node;
-
- public Shell(String domainURI) {
- this.node = nodeFactory.createNode(domainURI);
- }
-
+ private boolean useJline;
final List<String> history = new ArrayList<String>();
-
+ static final String[] COMMANDS = new String[] {"addDeploymentComposite", "addToDomainLevelComposite", "help",
+ "install", "listDeployedCompostes",
+ "printDomainLevelComposite", "listInstalledContributions",
+ "removeFromDomainLevelComposite", "remove", "status", "stop"};
+
public static void main(final String[] args) throws Exception {
- new Shell(args.length > 0 ? args[0] : "default").run();
+ boolean useJline = !Arrays.asList(args).contains("-nojline");
+ new Shell(args.length > 0 ? args[0] : "default", useJline).run();
+ }
+
+ public Shell(String domainURI, boolean useJLine) {
+ this.node = NodeFactory.newInstance().createNode(domainURI);
+ this.useJline = useJLine;
}
- boolean addDeploymentComposite(final String curi, String content) throws ContributionReadException, XMLStreamException, ActivationException, ValidationException {
- node.addDeploymentComposite(curi, new StringReader(content));
+ boolean addDeploymentComposite(final String curi, String contentURL) throws ContributionReadException, XMLStreamException, ActivationException, ValidationException, IOException {
+ node.addDeploymentComposite(curi, new StringReader(readContents(contentURL)));
return true;
}
@@ -70,14 +80,29 @@ public class Shell { return true;
}
- boolean install(final String cloc) throws ContributionReadException, ActivationException, ValidationException {
- String uri = getURI(cloc);
- node.installContribution(getURI(cloc), cloc, null, null, true);
- out.println("installed: " + uri);
+ boolean install(final String cloc, final List<String> toks) throws ContributionReadException, ActivationException, ValidationException {
+ boolean runDeployables = !toks.contains("-norun");
+ String uri;
+ if (toks.contains("-uri")) {
+ uri = toks.get(toks.indexOf("-uri")+1);
+ } else {
+ uri = getDefaultURI(cloc);
+ out.println("installing at: " + uri);
+ }
+ 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(","));
+ }
+
+ node.installContribution(uri, cloc, metaDataURL, duris, runDeployables);
return true;
}
- private String getURI(String contributionURL) {
+ private String getDefaultURI(String contributionURL) {
int lastDot = contributionURL.lastIndexOf('.');
int lastSep = contributionURL.lastIndexOf("/");
String uri = contributionURL;
@@ -86,7 +111,7 @@ public class Shell { } else {
try {
File f = new File(contributionURL);
- if ("classes".equals(f.getName())) {
+ if ("classes".equals(f.getName()) && "target".equals(f.getParentFile().getName())) {
uri = f.getParentFile().getParentFile().getName();
}
} catch (Exception e) {
@@ -106,6 +131,7 @@ public class Shell { boolean listInstalledContributions() throws ContributionReadException, ActivationException, ValidationException {
for (String uri : node.getInstalledContributions()) {
out.println(uri);
+ listComposites(uri);
}
return true;
}
@@ -130,14 +156,24 @@ public class Shell { return true;
}
+ boolean listComposites(final String curi) {
+ Contribution c = node.getInstalledContribution(curi);
+ for (Artifact a : c.getArtifacts()) {
+ if (a.getModel() instanceof Composite) {
+ out.println(((Composite)a.getModel()).getName());
+ }
+ }
+ return true;
+ }
+
boolean help() {
out.println("Apache Tuscany Shell (" + Version.getVersion() + " " + Version.getRevsion() + " " + Version.getBuildTime() + ")");
out.println("Commands:");
out.println();
out.println(" help");
- out.println(" install <contributionURL>");
- out.println(" remove <contributionURL>");
- out.println(" addDeploymentComposite <contributionURL> <content>");
+ out.println(" install <contributionURL> [-uri <uri> -norun -metadata <url> -duris <uri,uri,...>]");
+ out.println(" remove <contributionURI>");
+ out.println(" addDeploymentComposite <contributionURI> <content>");
out.println(" addToDomainLevelComposite <contributionURI/compositeURI>");
out.println(" removeFromDomainLevelComposite <contributionURI/compositeURI>");
out.println(" listDeployedCompostes <contributionURI>");
@@ -170,14 +206,20 @@ public class Shell { out.println(l);
return true;
}
-
- List<String> read(final BufferedReader r) throws IOException {
+
+ List<String> read(Object r) throws IOException {
out.print("=> ");
- final String l = r.readLine();
- history.add(l);
- return Arrays.asList(l != null? l.trim().split(" ") : "bye".split(" "));
+ final String l;
+ if (useJline) {
+ l = JLine.readLine(r);
+ } else {
+ l = ((BufferedReader)r).readLine();
+ history.add(l);
+ }
+// history.add(l);
+ return Arrays.asList(l != null? l.trim().split(" ") : "stop".split(" "));
}
-
+
Callable<Boolean> eval(final List<String> toks) {
final String op = toks.get(0);
@@ -188,7 +230,7 @@ public class Shell { return addToDomainLevelComposite(toks.get(1));
}};
if (op.equals("install")) return new Callable<Boolean>() { public Boolean call() throws Exception {
- return install(toks.get(1));
+ return install(toks.get(1), toks);
}};
if (op.equals("listDeployedCompostes")) return new Callable<Boolean>() { public Boolean call() throws Exception {
return listDeployedCompostes(toks.get(1));
@@ -220,7 +262,11 @@ public class Shell { if (op.equals("history")) return new Callable<Boolean>() { public Boolean call() {
return history();
}};
+ if (op.equals("")) return new Callable<Boolean>() { public Boolean call() {
+ return true;
+ }};
return new Callable<Boolean>() { public Boolean call() {
+ out.println("unknown command");
return true;
}};
}
@@ -236,7 +282,29 @@ public class Shell { public void run() throws IOException {
help();
- final BufferedReader r = new BufferedReader(new InputStreamReader(in));
- while(apply(eval(read(r))));
+ Object reader;
+ if (useJline) {
+ reader = JLine.createJLineReader(this);
+ } else {
+ reader = new BufferedReader(new InputStreamReader(in));
+ }
+ while(apply(eval(read(reader))));
}
+
+ String readContents(String location) throws IOException {
+ URL url = IOHelper.getLocationAsURL(location);
+ InputStream is = IOHelper.openStream(url);
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ StringBuilder builder = new StringBuilder(8192);
+ for(String line=br.readLine(); line!=null; line=br.readLine()) {
+ builder.append(line);
+ builder.append('\n');
+ }
+ return builder.toString();
+ } finally {
+ IOHelper.close(is);
+ }
+ }
+
}
|