
org.graphwalker.cli.CLI Maven / Gradle / Ivy
package org.graphwalker.cli;
/*
* #%L
* GraphWalker Command Line Interface
* %%
* Copyright (C) 2005 - 2014 GraphWalker
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* #L%
*/
import com.beust.jcommander.JCommander;
import com.beust.jcommander.MissingCommandException;
import com.beust.jcommander.ParameterException;
import com.sun.jersey.api.container.grizzly2.GrizzlyServerFactory;
import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.grizzly.http.server.HttpServer;
import org.graphwalker.cli.commands.*;
import org.graphwalker.cli.util.LoggerUtil;
import org.graphwalker.core.event.EventType;
import org.graphwalker.core.event.Observer;
import org.graphwalker.core.machine.Context;
import org.graphwalker.core.machine.Machine;
import org.graphwalker.core.machine.MachineException;
import org.graphwalker.core.machine.SimpleMachine;
import org.graphwalker.core.model.Edge;
import org.graphwalker.core.model.Element;
import org.graphwalker.core.model.Requirement;
import org.graphwalker.core.model.Vertex;
import org.graphwalker.dsl.antlr.DslException;
import org.graphwalker.dsl.antlr.generator.GeneratorFactory;
import org.graphwalker.io.common.ResourceUtils;
import org.graphwalker.io.factory.ContextFactory;
import org.graphwalker.io.factory.ContextFactoryScanner;
import org.graphwalker.io.factory.gw3.GW3ContextFactory;
import org.graphwalker.java.test.TestExecutor;
import org.graphwalker.modelchecker.ContextsChecker;
import org.graphwalker.restful.Restful;
import org.graphwalker.restful.Util;
import org.graphwalker.websocket.WebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.graphwalker.core.model.Model.RuntimeModel;
public class CLI {
private static final Logger logger = LoggerFactory.getLogger(CLI.class);
private Offline offline;
private Online online;
private Methods methods;
private Requirements requirements;
private Convert convert;
private Source source;
private Check check;
enum Command {
NONE,
OFFLINE,
ONLINE,
METHODS,
REQUIREMENTS,
CONVERT,
SOURCE,
CHECK
}
private Command command = Command.NONE;
public static void main(String[] args) {
CLI cli = new CLI();
try {
cli.run(args);
} catch (Exception e) {
// We should have caught all exceptions up until here, but there
// might have been problems with the command parser for instance...
System.err.println(e + System.lineSeparator());
logger.error("An error occurred when running command: " + StringUtils.join(args, " "), e);
}
}
/**
* Parses the command line.
*
* @param args
*/
private void run(String[] args) {
Options options = new Options();
JCommander jc = new JCommander(options);
jc.setProgramName("java -jar graphwalker.jar");
try {
jc.parseWithoutValidation(args);
} catch (Exception e) {
// ignore
}
try {
setLogLevel(options);
if (options.help) {
options = new Options();
jc = new JCommander(options);
offline = new Offline();
jc.addCommand("offline", offline);
online = new Online();
jc.addCommand("online", online);
methods = new Methods();
jc.addCommand("methods", methods);
requirements = new Requirements();
jc.addCommand("requirements", requirements);
convert = new Convert();
jc.addCommand("convert", convert);
source = new Source();
jc.addCommand("source", source);
check = new Check();
jc.addCommand("check", check);
jc.parse(args);
jc.usage();
return;
} else if (options.version) {
System.out.println(printVersionInformation());
return;
}
// Need to instantiate options again to avoid
// ParameterException "Can only specify option --debug once."
options = new Options();
jc = new JCommander(options);
offline = new Offline();
jc.addCommand("offline", offline);
online = new Online();
jc.addCommand("online", online);
methods = new Methods();
jc.addCommand("methods", methods);
requirements = new Requirements();
jc.addCommand("requirements", requirements);
convert = new Convert();
jc.addCommand("convert", convert);
source = new Source();
jc.addCommand("source", source);
check = new Check();
jc.addCommand("check", check);
jc.parse(args);
// Parse for commands
if (jc.getParsedCommand() != null) {
if (jc.getParsedCommand().equalsIgnoreCase("offline")) {
command = Command.OFFLINE;
RunCommandOffline();
} else if (jc.getParsedCommand().equalsIgnoreCase("online")) {
command = Command.ONLINE;
RunCommandOnline();
} else if (jc.getParsedCommand().equalsIgnoreCase("methods")) {
command = Command.METHODS;
RunCommandMethods();
} else if (jc.getParsedCommand().equalsIgnoreCase("requirements")) {
command = Command.REQUIREMENTS;
RunCommandRequirements();
} else if (jc.getParsedCommand().equalsIgnoreCase("convert")) {
command = Command.CONVERT;
RunCommandConvert();
} else if (jc.getParsedCommand().equalsIgnoreCase("source")) {
command = Command.SOURCE;
RunCommandSource();
} else if (jc.getParsedCommand().equalsIgnoreCase("check")) {
command = Command.SOURCE;
RunCommandCheck();
}
}
// No commands or options were found
else {
throw new MissingCommandException("Missing a command. Add '--help'");
}
} catch (MissingCommandException e) {
System.err.println(e.getMessage() + System.lineSeparator());
} catch (ParameterException e) {
System.err.println("An error occurred when running command: " + StringUtils.join(args, " "));
System.err.println(e.getMessage() + System.lineSeparator());
if (jc.getParsedCommand() != null) {
jc.usage(jc.getParsedCommand());
}
} catch (Exception e) {
System.err.println("An error occurred when running command: " + StringUtils.join(args, " "));
System.err.println(e.getMessage() + System.lineSeparator());
logger.error("An error occurred when running command: " + StringUtils.join(args, " "), e);
}
}
private void setLogLevel(Options options) {
// OFF, ERROR, WARN, INFO, DEBUG, TRACE, ALL
if (options.debug.equalsIgnoreCase("OFF")) {
LoggerUtil.setLogLevel(LoggerUtil.Level.OFF);
} else if (options.debug.equalsIgnoreCase("ERROR")) {
LoggerUtil.setLogLevel(LoggerUtil.Level.ERROR);
} else if (options.debug.equalsIgnoreCase("WARN")) {
LoggerUtil.setLogLevel(LoggerUtil.Level.WARN);
} else if (options.debug.equalsIgnoreCase("INFO")) {
LoggerUtil.setLogLevel(LoggerUtil.Level.INFO);
} else if (options.debug.equalsIgnoreCase("DEBUG")) {
LoggerUtil.setLogLevel(LoggerUtil.Level.DEBUG);
} else if (options.debug.equalsIgnoreCase("TRACE")) {
LoggerUtil.setLogLevel(LoggerUtil.Level.TRACE);
} else if (options.debug.equalsIgnoreCase("ALL")) {
LoggerUtil.setLogLevel(LoggerUtil.Level.ALL);
} else {
throw new ParameterException("Incorrect argument to --debug");
}
}
private void RunCommandCheck() throws Exception {
List contexts = getContextsWithPathGenerators(check.model.iterator());
List issues = ContextsChecker.hasIssues(contexts);
if (!issues.isEmpty()) {
for (String issue : issues) {
System.out.println(issue);
}
} else {
System.out.println("No issues found with the model(s).");
}
}
private void RunCommandRequirements() throws Exception {
SortedSet reqs = new TreeSet<>();
for (Context context : getContexts(requirements.model.iterator())) {
for (Requirement req : context.getRequirements()) {
reqs.add(req.getKey());
}
}
for (String req : reqs) {
System.out.println(req);
}
}
private void RunCommandMethods() throws Exception {
SortedSet names = new TreeSet<>();
for (Context context : getContexts(methods.model.iterator())) {
for (Vertex.RuntimeVertex vertex : context.getModel().getVertices()) {
if (null != vertex.getName()) {
names.add(vertex.getName());
}
}
for (Edge.RuntimeEdge edge : context.getModel().getEdges()) {
if (edge.getName() != null) {
names.add(edge.getName());
}
}
}
for (String name : names) {
System.out.println(name);
}
}
private void RunCommandOnline() throws Exception {
if (online.service.equalsIgnoreCase(Online.SERVICE_WEBSOCKET)) {
WebSocketServer GraphWalkerWebSocketServer = new WebSocketServer(online.port);
try {
GraphWalkerWebSocketServer.startService();
} catch (Exception e) {
logger.error("Something went wrong.", e);
}
} else if (online.service.equalsIgnoreCase(Online.SERVICE_RESTFUL)) {
ResourceConfig rc = new DefaultResourceConfig();
try {
rc.getSingletons().add(new Restful(getContextsWithPathGenerators(online.model.iterator()), online.verbose, online.unvisited));
} catch (MachineException e) {
System.err.println("Was the argument --model correctly?");
throw e;
}
String url = "http://0.0.0.0:" + online.port;
HttpServer server = GrizzlyServerFactory.createHttpServer(url, rc);
System.out.println("Try http://localhost:"
+ online.port
+ "/graphwalker/hasNext or http://localhost:"
+ online.port
+ "/graphwalker/getNext");
System.out.println("Press Control+C to end...");
try {
server.start();
Thread.currentThread().join();
} catch (Exception e) {
logger.error("An error occurred when running command online: ", e);
} finally {
server.stop();
}
} else {
throw new ParameterException("--service expected either WEBSOCKET or RESTFUL");
}
}
private void RunCommandConvert() throws Exception {
String inputFileName = convert.input.get(0);
String outputFileName = convert.input.get(1);
ContextFactory inputFactory = ContextFactoryScanner.get(Paths.get(inputFileName));
Context context;
try {
context = inputFactory.create(Paths.get(inputFileName));
} catch (DslException e) {
System.err.println("When parsing model: '" + inputFileName + "' " + e.getMessage() + System.lineSeparator());
throw new Exception("Model syntax error");
}
ContextFactory outputFactory = ContextFactoryScanner.get(Paths.get(outputFileName));
outputFactory.write(context, Paths.get(outputFileName));
}
private void RunCommandSource() throws Exception {
String modelFileName = source.input.get(0);
String templateFileName = source.input.get(1);
// Read the model
ContextFactory inputFactory = ContextFactoryScanner.get(Paths.get(modelFileName));
Context context;
try {
context = inputFactory.create(Paths.get(modelFileName));
} catch (DslException e) {
System.err.println("When parsing model: '" + modelFileName + "' " + e.getMessage() + System.lineSeparator());
throw new Exception("Model syntax error");
}
SortedSet names = new TreeSet<>();
for (Vertex.RuntimeVertex vertex : context.getModel().getVertices()) {
if (vertex.hasName()) {
names.add(vertex.getName());
}
}
for (Edge.RuntimeEdge edge : context.getModel().getEdges()) {
if (edge.hasName()) {
names.add(edge.getName());
}
}
// Read the template
StringBuilder templateStrBuilder = new StringBuilder();
String line;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(ResourceUtils.getResourceAsStream(templateFileName)))) {
while ((line = reader.readLine()) != null) {
templateStrBuilder.append(line).append("\n");
}
} catch (IOException e) {
logger.error(e.getMessage());
throw new RuntimeException("Could not read the file: " + templateFileName);
}
String templateStr = templateStrBuilder.toString();
// Apply the template and generate the source code to std out
String header = "", body = "", footer = "";
Pattern p = Pattern.compile("HEADER<\\{\\{([.\\s\\S]+)\\}\\}>HEADER([.\\s\\S]+)FOOTER<\\{\\{([.\\s\\S]+)\\}\\}>FOOTER");
Matcher m = p.matcher(templateStr);
if (m.find()) {
header = m.group(1);
body = m.group(2);
footer = m.group(3);
}
System.out.println(header);
for (String name : names) {
System.out.println(body.replaceAll("\\{LABEL\\}", name));
}
System.out.println(footer);
}
private void RunCommandOffline() throws Exception {
if (offline.model.size() > 0) {
TestExecutor executor = new TestExecutor(getContextsWithPathGenerators(offline.model.iterator()));
executor.getMachine().addObserver(new Observer() {
@Override
public void update(Machine machine, Element element, EventType type) {
if (EventType.BEFORE_ELEMENT.equals(type)) {
System.out.println(Util.getStepAsJSON(machine, offline.verbose, offline.unvisited).toString());
}
}
});
executor.execute();
} else if (!offline.gw3.isEmpty()) {
SimpleMachine machine = new SimpleMachine(new GW3ContextFactory().createMultiple(Paths.get(offline.gw3)));
while (machine.hasNextStep()) {
machine.getNextStep();
System.out.println(Util.getStepAsJSON(machine, offline.verbose, offline.unvisited).toString());
}
}
}
public List getContextsWithPathGenerators(Iterator itr) throws Exception {
List executionContexts = new ArrayList<>();
boolean triggerOnce = true;
while (itr.hasNext()) {
String modelFileName = (String) itr.next();
ContextFactory factory = ContextFactoryScanner.get(Paths.get(modelFileName));
Context context;
try {
context = factory.create(Paths.get(modelFileName));
} catch (DslException e) {
System.err.println("When parsing model: '" + modelFileName + "' " + e.getMessage() + System.lineSeparator());
throw new Exception("Model syntax error");
}
context.setPathGenerator(GeneratorFactory.parse((String) itr.next()));
if (triggerOnce &&
(!offline.startElement.isEmpty() ||
(!online.startElement.isEmpty()))) {
triggerOnce = false;
List elements = null;
if (command == Command.OFFLINE) {
elements = context.getModel().findElements(offline.startElement);
} else if (command == Command.ONLINE) {
elements = context.getModel().findElements(online.startElement);
}
if (elements == null) {
throw new ParameterException("--start-element Did not find matching element in the model: " + modelFileName);
} else if (elements.size() > 1) {
throw new ParameterException("--start-element There are more than one matching element in the model: " + modelFileName);
}
context.setNextElement(elements.get(0));
}
executionContexts.add(context);
}
return executionContexts;
}
private List getContexts(Iterator itr) throws Exception {
List executionContexts = new ArrayList<>();
while (itr.hasNext()) {
String modelFileName = (String) itr.next();
ContextFactory factory = ContextFactoryScanner.get(Paths.get(modelFileName));
Context context;
try {
context = factory.create(Paths.get(modelFileName));
} catch (DslException e) {
System.err.println("When parsing model: '" + modelFileName + "' " + e.getMessage() + System.lineSeparator());
throw new Exception("Model syntax error");
}
executionContexts.add(context);
}
return executionContexts;
}
private void verifyModel(RuntimeModel model) {
// Verify that the model has more than 1 vertex
if (model.getVertices().size() < 1) {
throw new RuntimeException("Model has less than 1 vertices. [Excluding the Start vertex]");
}
// Verify that the model has more than 0 edges
if (model.getEdges().size() < 1) {
throw new RuntimeException("Model has less than 1 edge.");
}
}
private String printVersionInformation() {
String version = "org.graphwalker version: " + getVersionString() + System.getProperty("line.separator");
version += System.getProperty("line.separator");
version += "org.graphwalker is open source software licensed under MIT license" + System.getProperty("line.separator");
version += "The software (and it's source) can be downloaded from http://graphwalker.org" + System.getProperty("line.separator");
version += "For a complete list of this package software dependencies, see http://graphwalker.org/archive/site/graphwalker-cli/dependencies.html" + System.getProperty("line.separator");
return version;
}
private String getVersionString() {
Properties properties = new Properties();
InputStream inputStream = getClass().getResourceAsStream("/version.properties");
if (null != inputStream) {
try {
properties.load(inputStream);
} catch (IOException e) {
logger.error("An error occurred when trying to get the version string", e);
return "unknown";
}
}
return properties.getProperty("graphwalker.version");
}
private String generateListOfValidGenerators() {
return "";
}
private String generateListOfValidStopConditions() {
return "";
}
private boolean helpNeeded(String module, boolean condition, String message) {
if (condition) {
System.out.println(message);
System.out.println("Type 'java -jar graphwalker.jar help " + module + "' for help.");
}
return condition;
}
public Online getOnline() {
return online;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy