All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tuscany.sca.shell.Shell Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
/*
 * 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.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;
        for (String s : args) {
            if ("-nojline".equals(s)) {
                useJline = false;
            } else if ("-help".equals(s)) {
                showHelp = true;
            } else {
                if (s.startsWith("uri:") || s.startsWith("properties:")) {
                    domainURI = s;
                } else {
                    contribution = s;
                }
            }
        }
        Shell 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(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:




© 2015 - 2024 Weber Informatics LLC | Privacy Policy