You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/23 11:18:59 UTC

[7/8] incubator-taverna-commandline git commit: Revert "temporarily empty repository"

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-common/src/main/resources/META-INF/spring/taverna-commandline-common-context-osgi.xml
----------------------------------------------------------------------
diff --git a/taverna-commandline-common/src/main/resources/META-INF/spring/taverna-commandline-common-context-osgi.xml b/taverna-commandline-common/src/main/resources/META-INF/spring/taverna-commandline-common-context-osgi.xml
new file mode 100644
index 0000000..e7ae701
--- /dev/null
+++ b/taverna-commandline-common/src/main/resources/META-INF/spring/taverna-commandline-common-context-osgi.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:beans="http://www.springframework.org/schema/beans"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                                 http://www.springframework.org/schema/beans/spring-beans.xsd
+                                 http://www.springframework.org/schema/osgi
+                                 http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+
+    <service ref="commandLineMasterPasswordProvider" interface="net.sf.taverna.t2.security.credentialmanager.MasterPasswordProvider" />
+
+ 	<reference id="commandLineOptions" interface="net.sf.taverna.t2.commandline.options.CommandLineOptions"/>
+    <reference id="runService" interface="uk.org.taverna.platform.run.api.RunService"/>
+	<reference id="credentialManager" interface="net.sf.taverna.t2.security.credentialmanager.CredentialManager" />
+	<reference id="databaseConfiguration" interface="uk.org.taverna.configuration.database.DatabaseConfiguration" />
+	<reference id="databaseManager" interface="uk.org.taverna.configuration.database.DatabaseManager" />
+
+	<reference id="workflowBundleIO" interface="uk.org.taverna.scufl2.api.io.WorkflowBundleIO" />
+	<reference id="t2flowWorkflowBundleReader" interface="uk.org.taverna.scufl2.api.io.WorkflowBundleReader" filter="(mediaType=application/vnd.taverna.t2flow+xml)"/>
+	<reference id="rdfXMLWorkflowBundleReader" interface="uk.org.taverna.scufl2.api.io.WorkflowBundleReader" filter="(org.springframework.osgi.bean.name=rdfXMLReader)"/>
+
+</beans:beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-common/src/main/resources/META-INF/spring/taverna-commandline-common-context.xml
----------------------------------------------------------------------
diff --git a/taverna-commandline-common/src/main/resources/META-INF/spring/taverna-commandline-common-context.xml b/taverna-commandline-common/src/main/resources/META-INF/spring/taverna-commandline-common-context.xml
new file mode 100644
index 0000000..52c0f29
--- /dev/null
+++ b/taverna-commandline-common/src/main/resources/META-INF/spring/taverna-commandline-common-context.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                           http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<bean id="commandLineTool" class="net.sf.taverna.t2.commandline.CommandLineTool" init-method="run">
+		<property name="commandLineOptions" ref="commandLineOptions" />
+		<property name="runService" ref="runService" />
+		<property name="credentialManager" ref="credentialManager" />
+		<property name="workflowBundleIO" ref="workflowBundleIO" />
+		<property name="databaseConfiguration" ref="databaseConfiguration" />
+		<property name="databaseManager" ref="databaseManager" />
+	</bean>
+
+	<bean id="commandLineMasterPasswordProvider"
+		class="net.sf.taverna.t2.commandline.CommandLineMasterPasswordProvider">
+		<constructor-arg name="commandLineOptions"
+			ref="commandLineOptions" />
+	</bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-common/src/main/resources/database-defaults.properties
----------------------------------------------------------------------
diff --git a/taverna-commandline-common/src/main/resources/database-defaults.properties b/taverna-commandline-common/src/main/resources/database-defaults.properties
new file mode 100644
index 0000000..1080856
--- /dev/null
+++ b/taverna-commandline-common/src/main/resources/database-defaults.properties
@@ -0,0 +1,11 @@
+in_memory = true
+provenance = false
+connector = derby
+port = 1527 
+dialect = org.hibernate.dialect.DerbyDialect
+start_derby = false
+pool_max_active = 50
+pool_min_idle = 50
+pool_max_idle = 10
+driver = org.apache.derby.jdbc.EmbeddedDriver
+jdbcuri = jdbc:derby:t2-database;create=true;upgrade=true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-common/src/main/resources/help.txt
----------------------------------------------------------------------
diff --git a/taverna-commandline-common/src/main/resources/help.txt b/taverna-commandline-common/src/main/resources/help.txt
new file mode 100644
index 0000000..fb082cc
--- /dev/null
+++ b/taverna-commandline-common/src/main/resources/help.txt
@@ -0,0 +1,87 @@
+By default, the workflow is executed using the -inmemory option, and the
+results are written out to a directory named after the workflow name.
+
+If this directory already exists then a new directory is created, and
+appended with _<n>, where n is incremented to the next available index.
+
+Results are written out to files named after the output port for that result.
+If a result is composed of lists, then a directory is created for the output
+port and individual list items are named after the list element index (with 1
+being the first index). The the output is the result of an error, the filename
+is appended with '.error'.
+
+You can provide your own output directory with the -outputdir option. There
+will be an error if the directory already exists.
+
+You can also record your results to a Baclava document using -outputdoc
+option. The document will be overwritten if it already exists.
+
+Inputs can be provided in three ways. Both -inputfile and -inputvalue options
+can be used together; -inputdoc option must be used on its own. -inputfile and
+-inputvalue options both take two additional arguments, the name of the port
+for the input, and either a file containing the input data, or the input value
+itself respectively.
+
+If one of more of your workflow inputs is a list, you can create a list
+input by using the -inputdelimiter option, which may be used with either
+-inputfile or -inputvalue. This option takes two parameters - an input name
+and the delimiter by which to split the input into a list.
+
+The delimiter may be a simple character, such as a comma or a new-line
+character, or a regular expression. The input string, or file, will then be
+converted into a list being split by the delimiter specified. Make sure to 
+put the delimiter character in quotes as it may be interpreted by the shell 
+as a special character, e.g. ;.
+
+If a list of greater depth (i.e. a list or lists or deeper) is required then
+you will need to use the -inputdoc option.  However, if you provide an input
+of lower depth to that required, then it will automatically be wrapped in one
+or more lists up to the required depth. Providing an input of greater depth
+than that required will result in an error.
+
+If a workflow has a high memory requirement, then it may be better to run it
+using a database to store data rather than storing it in memory, which is the
+default option. There are three options for using a database:
+
+-embedded option, runs with an embedded database. This is slightly faster than
+the -clientserver option (below), but has the limitation that only one
+executeworkflow script may be executed simultaneously.
+
+-clientserver option allows the workflow to be executed backed by the database
+running as a server. By default a database is not started for you, but may be
+started using -startdb option.
+
+-startdb option starts a database. It may be used without providing a workflow
+to allow a database to be started separately, allowing multiple simultaneous
+executeworkflow script runs.
+
+More advanced database configurations can be specified using -dbproperties
+option, allowing you to take full control over the database used. This takes a
+second argument, the filename of the properties file, for which the following
+example contains the default settings:
+
+in_memory = true
+provenance = false
+connector = derby
+port = 1527
+dialect = org.hibernate.dialect.DerbyDialect
+start_derby = false
+driver = org.apache.derby.jdbc.EmbeddedDriver
+jdbcuri = jdbc:derby:t2-database;create=true;upgrade=true
+
+Note that when using -dbproperties together with other options, the other
+options take precedence.
+
+-cmdir option lets you specify an absolute path to a directory where 
+Credential Manager's files (keystore and truststore - containing user's 
+credentials and trusted certificates for accessing secure services) are stored.
+If not specified and the workflow requires access to these files, Taverna will 
+try to find them in the default location in <TAVERNA_HOME>/security somewhere 
+inside user's home directory (depending on the platform).
+
+-cmpassword option can be used to tell Taverna to expect the password for the 
+Credential Manager on standard input. If the password is not piped in, Taverna 
+will prompt you for it in the terminal and block until it is entered. Do not 
+enter your password in the command line! If -cmpassword option is not specified 
+and -cmdir option is used, Taverna will try to find the password in a special 
+file password.txt in the directory specified with -cmdir option.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-common/src/test/java/net/sf/taverna/t2/commandline/TestDatabaseConfigurationHandler.java
----------------------------------------------------------------------
diff --git a/taverna-commandline-common/src/test/java/net/sf/taverna/t2/commandline/TestDatabaseConfigurationHandler.java b/taverna-commandline-common/src/test/java/net/sf/taverna/t2/commandline/TestDatabaseConfigurationHandler.java
new file mode 100644
index 0000000..4c00e3a
--- /dev/null
+++ b/taverna-commandline-common/src/test/java/net/sf/taverna/t2/commandline/TestDatabaseConfigurationHandler.java
@@ -0,0 +1,21 @@
+package net.sf.taverna.t2.commandline;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.taverna.t2.commandline.data.DatabaseConfigurationHandler;
+import net.sf.taverna.t2.commandline.options.CommandLineOptions;
+//import net.sf.taverna.t2.workbench.reference.config.DataManagementConfiguration;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class TestDatabaseConfigurationHandler {
+
+//	@Test
+//	public void testDefaults() throws Exception {
+//		CommandLineOptions opts = new CommandLineOptions(new String[]{"myworkflow.t2flow"});
+//		DatabaseConfigurationHandler handler = new DatabaseConfigurationHandler(opts);
+//		handler.configureDatabase();
+//		assertEquals("org.apache.derby.jdbc.EmbeddedDriver", DataManagementConfiguration.getInstance().getDriverClassName());
+//		assertEquals(false, DataManagementConfiguration.getInstance().getStartInternalDerbyServer());
+//	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-launcher/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-commandline-launcher/pom.xml b/taverna-commandline-launcher/pom.xml
new file mode 100644
index 0000000..42208e3
--- /dev/null
+++ b/taverna-commandline-launcher/pom.xml
@@ -0,0 +1,83 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.commandline</groupId>
+		<artifactId>taverna-commandline</artifactId>
+		<version>3.1.0.incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-commandline-launcher</artifactId>
+	<name>Apache Taverna Commandline Launcher</name>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<version>2.4</version>
+				<configuration>
+					<archive>
+						<manifest>
+							<addClasspath>true</addClasspath>
+							<mainClass>uk.org.taverna.commandline.TavernaCommandLine</mainClass>
+							<classpathLayoutType>custom</classpathLayoutType>
+							<customClasspathLayout>../${artifact.groupId}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</customClasspathLayout>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+	<dependencies>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-commandline-api</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.osgi</groupId>
+			<artifactId>osgi-launcher</artifactId>
+			<version>${taverna.osgi.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.osgi</groupId>
+			<artifactId>taverna-app-configuration-impl</artifactId>
+			<version>${taverna.osgi.version}</version>
+		</dependency>
+
+ 		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>com.springsource.org.apache.commons.cli</artifactId>
+			<version>${commons.cli.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>${commons.io.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>log4j</groupId>
+			<artifactId>log4j</artifactId>
+			<version>${log4j.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.eclipse</groupId>
+			<artifactId>org.eclipse.osgi</artifactId>
+			<version>${osgi.equinox.version}</version>
+		</dependency>
+    <!-- TODO: replace equinox with:
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.main</artifactId>
+      <version>4.4.1</version>
+    </dependency>
+    -->
+
+
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>${junit.version}</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-launcher/src/main/java/uk/org/taverna/commandline/CommandLineOptionsImpl.java
----------------------------------------------------------------------
diff --git a/taverna-commandline-launcher/src/main/java/uk/org/taverna/commandline/CommandLineOptionsImpl.java b/taverna-commandline-launcher/src/main/java/uk/org/taverna/commandline/CommandLineOptionsImpl.java
new file mode 100644
index 0000000..b702e03
--- /dev/null
+++ b/taverna-commandline-launcher/src/main/java/uk/org/taverna/commandline/CommandLineOptionsImpl.java
@@ -0,0 +1,445 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.commandline;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import net.sf.taverna.t2.commandline.exceptions.ArgumentsParsingException;
+import net.sf.taverna.t2.commandline.exceptions.InvalidOptionException;
+import net.sf.taverna.t2.commandline.options.CommandLineOptions;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+
+/**
+ * Handles the processing of command line arguments for enacting a workflow.
+ * This class encapsulates all command line options, and exposes them through higher-level
+ * accessors. Upon creation it checks the validity of the command line options and raises an
+ * {@link InvalidOptionException} if they are invalid.
+ *
+ * @author Stuart Owen
+ * @author David Withers
+ */
+public class CommandLineOptionsImpl implements CommandLineOptions {
+
+	private static final String OUTPUTDIR = "outputdir";
+	private static final String BUNDLE = "bundle";
+	private static final Logger logger = Logger.getLogger(CommandLineOptionsImpl.class);
+	private Options options;
+	private CommandLine commandLine;
+
+	public CommandLineOptionsImpl(String[] args) throws ArgumentsParsingException, InvalidOptionException {
+		this.options = intitialiseOptions();
+		this.commandLine = processArgs(args);
+		checkForInvalid();
+	}
+
+	@Override
+	public boolean askedForHelp() {
+		return hasOption("help") || (getArgs().length==0 && getOptions().length==0);
+	}
+
+	@Override
+	public boolean isProvenanceEnabled() {
+		return hasOption("provenance");
+	}
+
+	protected void checkForInvalid() throws InvalidOptionException {
+		if (askedForHelp()) return;
+		if (isProvenanceEnabled()
+				&& !(hasOption("embedded") || hasOption("clientserver") || hasOption("dbproperties")))
+			throw new InvalidOptionException(
+					"You should be running with a database to use provenance");
+		if (isProvenanceEnabled() && hasOption("inmemory"))
+			throw new InvalidOptionException(
+					"You should be running with a database to use provenance");
+		if ((hasOption("inputfile") || hasOption("inputvalue"))
+				&& hasOption("inputdoc"))
+			throw new InvalidOptionException(
+					"You can't provide both -input and -inputdoc arguments");
+
+		if (hasOption("inputdelimiter") && hasOption("inputdoc"))
+			throw new InvalidOptionException("You cannot combine the -inputdelimiter and -inputdoc arguments");
+
+		if (getArgs().length == 0
+				&& !(hasOption("help") || hasOption("startdb")))
+			throw new InvalidOptionException("You must specify a workflow");
+
+		if (hasOption("inmemory") && hasOption("embedded"))
+			throw new InvalidOptionException(
+					"The options -embedded, -clientserver and -inmemory cannot be used together");
+		if (hasOption("inmemory") && hasOption("clientserver"))
+			throw new InvalidOptionException(
+					"The options -embedded, -clientserver and -inmemory cannot be used together");
+		if (hasOption("embedded") && hasOption("clientserver"))
+			throw new InvalidOptionException(
+					"The options -embedded, -clientserver and -inmemory cannot be used together");
+	}
+
+	@Override
+	public void displayHelp() {
+		boolean full = false;
+		if (hasOption("help")) full=true;
+		displayHelp(full);
+	}
+
+	@Override
+	public void displayHelp(boolean showFullText) {
+
+		HelpFormatter formatter = new HelpFormatter();
+		try {
+			formatter
+					.printHelp("executeworkflow [options] [workflow]", options);
+			if (showFullText) {
+				InputStream helpStream = CommandLineOptionsImpl.class
+						.getClassLoader().getResourceAsStream("help.txt");
+				String helpText = IOUtils.toString(helpStream);
+				System.out.println(helpText);
+			}
+
+		} catch (IOException e) {
+			logger.error("Failed to load the help document", e);
+			System.out.println("Failed to load the help document");
+			//System.exit(-1);
+		}
+	}
+
+	@Override
+	public String[] getArgs() {
+		return commandLine.getArgs();
+	}
+
+	/**
+	 *
+	 * @return the port that the database should run on
+	 */
+	@Override
+	public String getDatabasePort() {
+		return getOptionValue("port");
+	}
+
+	/**
+	 *
+	 * @return a path to a properties file that contains database configuration
+	 *         settings
+	 */
+	@Override
+	public String getDatabaseProperties() {
+		return getOptionValue("dbproperties");
+	}
+
+	/**
+	 * Returns an array that alternates between a portname and path to a file
+	 * containing the input values. Therefore the array will always contain an
+	 * even number of elements
+	 *
+	 * @return an array of portname and path to files containing individual
+	 *         inputs.
+	 */
+	@Override
+	public String[] getInputFiles() {
+		if (hasInputFiles()) {
+			return getOptionValues("inputfile");
+		} else {
+			return new String[] {};
+		}
+	}
+
+	@Override
+	public String[] getInputValues() {
+		if (hasInputValues()) {
+			return getOptionValues("inputvalue");
+		} else {
+			return new String[] {};
+		}
+	}
+
+	@Override
+	public String getLogFile() {
+		return getOptionValue("logfile");
+	}
+
+	public Option [] getOptions() {
+		return commandLine.getOptions();
+	}
+
+	private String getOptionValue(String opt) {
+		return commandLine.getOptionValue(opt);
+	}
+
+	private String[] getOptionValues(String arg0) {
+		return commandLine.getOptionValues(arg0);
+	}
+
+	/**
+	 *
+	 * @return the directory to write the results to
+	 */
+	@Override
+	public String getOutputDirectory() {
+		return getOptionValue(OUTPUTDIR);
+	}
+
+	@Override
+	public boolean getStartDatabase() {
+		return hasOption("startdb");
+	}
+
+	/**
+	 * @return the directory with Credential Manager's files
+	 */
+	@Override
+	public String getCredentialManagerDir() {
+		return getOptionValue(CREDENTIAL_MANAGER_DIR_OPTION);
+	}
+
+	@Override
+	public boolean getStartDatabaseOnly() throws InvalidOptionException {
+		return (getStartDatabase() && (getWorkflow() == null));
+	}
+
+	@Override
+	public String getWorkflow() throws InvalidOptionException {
+		if (getArgs().length == 0) {
+			return null;
+		} else if (getArgs().length != 1) {
+			throw new InvalidOptionException(
+					"You should only specify one workflow file");
+		} else {
+			return getArgs()[0];
+		}
+	}
+
+	@Override
+	public boolean hasDelimiterFor(String inputName) {
+		boolean result = false;
+		if (hasOption("inputdelimiter")) {
+			String [] values = getOptionValues("inputdelimiter");
+			for (int i=0;i<values.length;i+=2) {
+				if (values[i].equals(inputName))
+				{
+					result=true;
+					break;
+				}
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public boolean hasInputFiles() {
+		return hasOption("inputfile");
+	}
+
+	@Override
+	public boolean hasInputValues() {
+		return hasOption("inputvalue");
+	}
+
+	@Override
+	public boolean hasLogFile() {
+		return hasOption("logfile");
+	}
+
+	@Override
+	public boolean hasOption(String option) {
+		return commandLine.hasOption(option);
+	}
+
+	@Override
+	public String inputDelimiter(String inputName) {
+		String result = null;
+		if (hasOption("inputdelimiter")) {
+			String [] values = getOptionValues("inputdelimiter");
+			for (int i=0;i<values.length;i+=2) {
+				if (values[i].equals(inputName))
+				{
+					result=values[i+1];
+					break;
+				}
+			}
+		}
+		return result;
+	}
+
+	@SuppressWarnings("static-access")
+	private Options intitialiseOptions() {
+		Option helpOption = new Option("help", "Display comprehensive help information.");
+
+		Option outputOption = OptionBuilder
+				.withArgName("directory")
+				.hasArg()
+				.withDescription(
+						"Save outputs as files in directory, default "
+								+ "is to make a new directory workflowName_output.")
+				.create(OUTPUTDIR);
+
+		Option bundleOption = OptionBuilder.withArgName(BUNDLE).hasArg()
+				.withDescription("Save outputs to a new Workflow Run Bundle (zip).")
+				.create(BUNDLE);
+
+		Option logFileOption = OptionBuilder
+				.withArgName("filename")
+				.hasArg()
+				.withDescription(
+						"The logfile to which more verbose logging will be written to.")
+				.create("logfile");
+
+		Option inputdocOption = OptionBuilder.withArgName("document").hasArg()
+				.withDescription("Load inputs from a Baclava document.").create(
+						"inputdoc");
+
+		Option inputFileOption = OptionBuilder
+				.withArgName("inputname filename").hasArgs(2)
+				.withValueSeparator(' ').withDescription(
+						"Load the named input from file or URL.").create(
+						"inputfile");
+
+		Option inputValueOption = OptionBuilder.withArgName("inputname value")
+				.hasArgs(2).withValueSeparator(' ').withDescription(
+						"Directly use the value for the named input.").create(
+						"inputvalue");
+
+		Option inputDelimiterOption = OptionBuilder
+				.withArgName("inputname delimiter")
+				.hasArgs(2)
+				.withValueSeparator(' ')
+				.withDescription(
+						"Cause an inputvalue or inputfile to be split into a list according to the delimiter. The associated workflow input must be expected to receive a list.")
+				.create("inputdelimiter");
+
+		Option dbProperties = OptionBuilder.withArgName("filename").hasArg()
+				.withDescription(
+						"Load a properties file to configure the database.")
+				.create("dbproperties");
+
+		Option port = OptionBuilder
+				.withArgName("portnumber")
+				.hasArg()
+				.withDescription(
+						"The port that the database is running on. If set requested to start its own internal server, this is the start port that will be used.")
+				.create("port");
+
+		Option embedded = new Option("embedded",
+				"Connect to an embedded Derby database. This can prevent mulitple invocations.");
+		Option clientserver = new Option("clientserver",
+				"Connect as a client to a derby server instance.");
+		Option inMemOption = new Option(
+				"inmemory",
+				"Run the workflow with data stored in-memory rather than in a database (this is the default option). This can give performance inprovements, at the cost of overall memory usage.");
+		Option startDB = new Option("startdb",
+				"Automatically start an internal Derby database server.");
+		Option provenance = new Option("provenance",
+				"Generate provenance information and store it in the database.");
+
+
+		Option credentialManagerDirectory = OptionBuilder.withArgName("directory path").
+		hasArg().withDescription(
+				"Absolute path to a directory where Credential Manager's files (keystore and truststore) are located.")
+		.create(CREDENTIAL_MANAGER_DIR_OPTION);
+		Option credentialManagerPassword = new Option(CREDENTIAL_MANAGER_PASSWORD_OPTION, "Indicate that the master password for Credential Manager will be provided on standard input."); // optional password option, to be read from standard input
+
+		Options options = new Options();
+		options.addOption(helpOption);
+		options.addOption(inputFileOption);
+		options.addOption(inputValueOption);
+		options.addOption(inputDelimiterOption);
+		options.addOption(inputdocOption);
+		options.addOption(outputOption);
+		options.addOption(bundleOption);
+		options.addOption(inMemOption);
+		options.addOption(embedded);
+		options.addOption(clientserver);
+		options.addOption(dbProperties);
+		options.addOption(port);
+		options.addOption(startDB);
+		options.addOption(provenance);
+		options.addOption(logFileOption);
+		options.addOption(credentialManagerDirectory);
+		options.addOption(credentialManagerPassword);
+
+		return options;
+	}
+
+	@Override
+	public boolean isClientServer() {
+		return hasOption("clientserver");
+	}
+
+	@Override
+	public boolean isEmbedded() {
+		return hasOption("embedded");
+	}
+
+	@Override
+	public boolean isInMemory() {
+		return hasOption("inmemory");
+	}
+
+	private CommandLine processArgs(String[] args) throws ArgumentsParsingException {
+		CommandLineParser parser = new GnuParser();
+		CommandLine line = null;
+		try {
+			// parse the command line arguments
+			line = parser.parse(options, args);
+		} catch (ParseException exp) {
+			// oops, something went wrong
+//			System.err.println("Taverna command line arguments' parsing failed. Reason: " + exp.getMessage());
+//			System.exit(1);
+			throw new ArgumentsParsingException("Taverna command line arguments' parsing failed. Reason: " + exp.getMessage(), exp);
+		}
+		return line;
+	}
+
+	/**
+	 * Save the results to a directory if -outputdir has been explicitly defined,
+	 * or if -outputdoc has not been defined.
+	 *
+	 * @return boolean
+	 */
+	@Override
+	public boolean saveResultsToDirectory() {
+		return (options.hasOption(OUTPUTDIR) || !hasSaveResultsToBundle());
+	}
+
+	@Override
+	public String saveResultsToBundle() {
+		if (! hasSaveResultsToBundle()) { 
+			return null;
+		}
+		return getOptionValue(BUNDLE);
+	}
+
+	@Override
+	public boolean hasSaveResultsToBundle() {
+		return hasOption(BUNDLE);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-launcher/src/main/java/uk/org/taverna/commandline/TavernaCommandLine.java
----------------------------------------------------------------------
diff --git a/taverna-commandline-launcher/src/main/java/uk/org/taverna/commandline/TavernaCommandLine.java b/taverna-commandline-launcher/src/main/java/uk/org/taverna/commandline/TavernaCommandLine.java
new file mode 100644
index 0000000..426ab98
--- /dev/null
+++ b/taverna-commandline-launcher/src/main/java/uk/org/taverna/commandline/TavernaCommandLine.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (C) 2012 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.commandline;
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.taverna.t2.commandline.exceptions.ArgumentsParsingException;
+import net.sf.taverna.t2.commandline.exceptions.InvalidOptionException;
+import net.sf.taverna.t2.commandline.options.CommandLineOptions;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+
+import uk.org.taverna.commons.profile.xml.jaxb.ApplicationProfile;
+import uk.org.taverna.commons.profile.xml.jaxb.BundleInfo;
+import uk.org.taverna.commons.profile.xml.jaxb.FrameworkConfiguration;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.configuration.app.impl.ApplicationConfigurationImpl;
+import uk.org.taverna.configuration.app.impl.Log4JConfiguration;
+import uk.org.taverna.osgi.OsgiLauncher;
+
+/**
+ * Main entry point for starting the Taverna Command Line Tool.
+ *
+ * @author David Withers
+ */
+public class TavernaCommandLine {
+
+	private static final String COMMANDLINE_BUNDLE_NAME = "org.apache.taverna.commandline.taverna-commandline-common";
+
+	private static File commandlineBundle = null;
+
+	private static ApplicationConfiguration applicationConfiguration = new ApplicationConfigurationImpl();
+
+	private static Log4JConfiguration log4jConfiguration = new Log4JConfiguration();
+
+	/**
+	 * Starts the Taverna Command Line Tool.
+	 *
+	 * @param args
+	 *            Taverna Command Line arguments
+	 */
+	public static void main(final String[] args) {
+		try {
+			CommandLineOptions commandLineOptions = new CommandLineOptionsImpl(args);
+			if (commandLineOptions.askedForHelp()) {
+				commandLineOptions.displayHelp();
+			} else {
+				log4jConfiguration.setApplicationConfiguration(applicationConfiguration);
+				log4jConfiguration.prepareLog4J();
+				setDerbyPaths();
+				OsgiLauncher osgilauncher = new OsgiLauncher(getAppDirectory(), getBundleURIs());
+				setFrameworkConfiguration(osgilauncher);
+				osgilauncher.start();
+				BundleContext context = osgilauncher.getContext();
+				context.registerService("net.sf.taverna.t2.commandline.options.CommandLineOptions",
+						commandLineOptions, null);
+				osgilauncher.startServices(true);
+        if (commandlineBundle == null) {
+          System.err.println("Can't locate command line bundle " + COMMANDLINE_BUNDLE_NAME);
+          System.exit(1);
+        }
+				osgilauncher.startBundle(osgilauncher.installBundle(commandlineBundle.toURI()));
+			}
+		} catch (ArgumentsParsingException e) {
+			System.out.println(e.getMessage());
+		} catch (InvalidOptionException e) {
+			System.out.println(e.getMessage());
+		} catch (BundleException e) {
+			System.out.println(e.getMessage());
+		}
+	}
+
+	/**
+	 * Sets the OSGi Framework configuration.
+	 *
+	 * @param osgilauncher
+	 */
+	private static void setFrameworkConfiguration(OsgiLauncher osgilauncher) {
+		ApplicationProfile applicationProfile = applicationConfiguration.getApplicationProfile();
+		List<FrameworkConfiguration> frameworkConfigurations = applicationProfile
+				.getFrameworkConfiguration();
+		if (!frameworkConfigurations.isEmpty()) {
+			Map<String, String> configurationMap = new HashMap<String, String>();
+			for (FrameworkConfiguration frameworkConfiguration : frameworkConfigurations) {
+				configurationMap.put(frameworkConfiguration.getName(),
+						frameworkConfiguration.getValue());
+			}
+			osgilauncher.setFrameworkConfiguration(configurationMap);
+		}
+	}
+
+	private static List<URI> getBundleURIs() {
+		List<URI> bundleURIs = new ArrayList<URI>();
+		ApplicationProfile applicationProfile = applicationConfiguration.getApplicationProfile();
+		File libDir = new File(applicationConfiguration.getStartupDir(), "lib");
+		if (applicationProfile != null) {
+			for (BundleInfo bundle : applicationProfile.getBundle()) {
+				File bundleFile = new File(libDir, bundle.getFileName());
+				if (bundle.getSymbolicName().equals(COMMANDLINE_BUNDLE_NAME)) {
+					commandlineBundle = bundleFile;
+				} else {
+					bundleURIs.add(bundleFile.toURI());
+				}
+			}
+		}
+		return bundleURIs;
+	}
+
+	private static File getAppDirectory() {
+		return new File(applicationConfiguration.getApplicationHomeDir().getAbsolutePath());
+	}
+
+	private static void setDerbyPaths() {
+		System.setProperty("derby.system.home", getAppDirectory().getAbsolutePath());
+		File logFile = new File(applicationConfiguration.getLogDir(), "derby.log");
+		System.setProperty("derby.stream.error.file", logFile.getAbsolutePath());
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-launcher/src/main/resources/help.txt
----------------------------------------------------------------------
diff --git a/taverna-commandline-launcher/src/main/resources/help.txt b/taverna-commandline-launcher/src/main/resources/help.txt
new file mode 100644
index 0000000..fb082cc
--- /dev/null
+++ b/taverna-commandline-launcher/src/main/resources/help.txt
@@ -0,0 +1,87 @@
+By default, the workflow is executed using the -inmemory option, and the
+results are written out to a directory named after the workflow name.
+
+If this directory already exists then a new directory is created, and
+appended with _<n>, where n is incremented to the next available index.
+
+Results are written out to files named after the output port for that result.
+If a result is composed of lists, then a directory is created for the output
+port and individual list items are named after the list element index (with 1
+being the first index). The the output is the result of an error, the filename
+is appended with '.error'.
+
+You can provide your own output directory with the -outputdir option. There
+will be an error if the directory already exists.
+
+You can also record your results to a Baclava document using -outputdoc
+option. The document will be overwritten if it already exists.
+
+Inputs can be provided in three ways. Both -inputfile and -inputvalue options
+can be used together; -inputdoc option must be used on its own. -inputfile and
+-inputvalue options both take two additional arguments, the name of the port
+for the input, and either a file containing the input data, or the input value
+itself respectively.
+
+If one of more of your workflow inputs is a list, you can create a list
+input by using the -inputdelimiter option, which may be used with either
+-inputfile or -inputvalue. This option takes two parameters - an input name
+and the delimiter by which to split the input into a list.
+
+The delimiter may be a simple character, such as a comma or a new-line
+character, or a regular expression. The input string, or file, will then be
+converted into a list being split by the delimiter specified. Make sure to 
+put the delimiter character in quotes as it may be interpreted by the shell 
+as a special character, e.g. ;.
+
+If a list of greater depth (i.e. a list or lists or deeper) is required then
+you will need to use the -inputdoc option.  However, if you provide an input
+of lower depth to that required, then it will automatically be wrapped in one
+or more lists up to the required depth. Providing an input of greater depth
+than that required will result in an error.
+
+If a workflow has a high memory requirement, then it may be better to run it
+using a database to store data rather than storing it in memory, which is the
+default option. There are three options for using a database:
+
+-embedded option, runs with an embedded database. This is slightly faster than
+the -clientserver option (below), but has the limitation that only one
+executeworkflow script may be executed simultaneously.
+
+-clientserver option allows the workflow to be executed backed by the database
+running as a server. By default a database is not started for you, but may be
+started using -startdb option.
+
+-startdb option starts a database. It may be used without providing a workflow
+to allow a database to be started separately, allowing multiple simultaneous
+executeworkflow script runs.
+
+More advanced database configurations can be specified using -dbproperties
+option, allowing you to take full control over the database used. This takes a
+second argument, the filename of the properties file, for which the following
+example contains the default settings:
+
+in_memory = true
+provenance = false
+connector = derby
+port = 1527
+dialect = org.hibernate.dialect.DerbyDialect
+start_derby = false
+driver = org.apache.derby.jdbc.EmbeddedDriver
+jdbcuri = jdbc:derby:t2-database;create=true;upgrade=true
+
+Note that when using -dbproperties together with other options, the other
+options take precedence.
+
+-cmdir option lets you specify an absolute path to a directory where 
+Credential Manager's files (keystore and truststore - containing user's 
+credentials and trusted certificates for accessing secure services) are stored.
+If not specified and the workflow requires access to these files, Taverna will 
+try to find them in the default location in <TAVERNA_HOME>/security somewhere 
+inside user's home directory (depending on the platform).
+
+-cmpassword option can be used to tell Taverna to expect the password for the 
+Credential Manager on standard input. If the password is not piped in, Taverna 
+will prompt you for it in the terminal and block until it is entered. Do not 
+enter your password in the command line! If -cmpassword option is not specified 
+and -cmdir option is used, Taverna will try to find the password in a special 
+file password.txt in the directory specified with -cmdir option.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-launcher/src/test/java/uk/org/taverna/commandline/TestCommandLineOptionsHandler.java
----------------------------------------------------------------------
diff --git a/taverna-commandline-launcher/src/test/java/uk/org/taverna/commandline/TestCommandLineOptionsHandler.java b/taverna-commandline-launcher/src/test/java/uk/org/taverna/commandline/TestCommandLineOptionsHandler.java
new file mode 100644
index 0000000..3e1d0f4
--- /dev/null
+++ b/taverna-commandline-launcher/src/test/java/uk/org/taverna/commandline/TestCommandLineOptionsHandler.java
@@ -0,0 +1,267 @@
+package uk.org.taverna.commandline;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import net.sf.taverna.t2.commandline.exceptions.InvalidOptionException;
+import net.sf.taverna.t2.commandline.options.CommandLineOptions;
+
+import org.junit.Test;
+
+public class TestCommandLineOptionsHandler {
+
+	@Test
+	public void testWorkflowName() throws Exception {
+		CommandLineOptions handler = new CommandLineOptionsImpl(
+				new String[] { "myworkflow.t2flow" });
+		assertEquals("myworkflow.t2flow", handler.getWorkflow());
+	}
+
+	@Test
+	public void shouldShowHelp() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(
+				new String[] { "-help" });
+		assertTrue(options.askedForHelp());
+		options = new CommandLineOptionsImpl(
+				new String[] {});
+		assertTrue(options.askedForHelp());
+		options = new CommandLineOptionsImpl(new String[] { "myworkflow.t2flow" });
+		assertFalse(options.askedForHelp());
+	}
+
+	@Test
+	public void getWorkflow() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(
+				new String[] { "-help" });
+		assertNull(options.getWorkflow());
+		options = new CommandLineOptionsImpl(new String[] { "myworkflow.t2flow" });
+		assertEquals("myworkflow.t2flow", options.getWorkflow());
+	}
+
+	@Test(expected = InvalidOptionException.class)
+	public void cannotProvideInputFileAndInputDoc() throws Exception {
+		new CommandLineOptionsImpl(new String[] { "-inputfile", "fred", "fred.txt",
+				"-inputdoc", "myworkflow.t2flow" });
+	}
+
+	@Test(expected = InvalidOptionException.class)
+	public void cannotProvideInputValueAndInputDoc() throws Exception {
+		new CommandLineOptionsImpl(new String[] { "-inputvalue", "fred", "fred.txt",
+				"-inputdoc", "myworkflow.t2flow" });
+	}
+
+	@Test
+	public void canProvideInputValueAndFileTogether() throws Exception {
+		//should not be an error
+		new CommandLineOptionsImpl(new String[] { "-inputvalue", "fred", "abc",
+				"-inputfile","fred2","fred2.txt","myworkflow.t2flow" });
+	}
+
+	@Test
+	public void getInputs() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-inputfile", "fred", "fred.txt", "myworkflow.t2flow" });
+		assertEquals(2, options.getInputFiles().length);
+		assertEquals("fred", options.getInputFiles()[0]);
+		assertEquals("fred.txt", options.getInputFiles()[1]);
+
+		options = new CommandLineOptionsImpl(new String[] { "-inputfile", "fred",
+				"fred.txt", "-inputfile", "fred2", "fred2.txt",
+				"myworkflow.t2flow" });
+		assertEquals(4, options.getInputFiles().length);
+		assertEquals("fred", options.getInputFiles()[0]);
+		assertEquals("fred.txt", options.getInputFiles()[1]);
+		assertEquals("fred2", options.getInputFiles()[2]);
+		assertEquals("fred2.txt", options.getInputFiles()[3]);
+
+		options = new CommandLineOptionsImpl(new String[] { "myworkflow.t2flow" });
+		assertNotNull(options.getInputFiles());
+		assertEquals(0, options.getInputFiles().length);
+
+	}
+
+	@Test
+	public void hasInputValue() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-inputvalue", "fred", "abc", "myworkflow.t2flow" });
+		assertTrue(options.hasInputValues());
+
+		options = new CommandLineOptionsImpl(new String[] { "myworkflow.t2flow" });
+		assertFalse(options.hasInputValues());
+	}
+
+	@Test
+	public void getInputValues() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-inputvalue", "fred", "abc", "myworkflow.t2flow" });
+		assertEquals(2, options.getInputValues().length);
+
+		options = new CommandLineOptionsImpl(new String[] { "myworkflow.t2flow" });
+		assertNotNull(options.getInputValues());
+		assertEquals(0,options.getInputValues().length);
+	}
+
+	@Test
+	public void hasInputs() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-inputfile", "fred", "fred.txt", "myworkflow.t2flow" });
+		assertTrue(options.hasInputFiles());
+
+		options = new CommandLineOptionsImpl(new String[] { "myworkflow.t2flow" });
+		assertFalse(options.hasInputFiles());
+	}
+
+	@Test
+	public void noWorkflowNameButStartDB() throws Exception {
+		// should not throw an error
+		CommandLineOptions options = new CommandLineOptionsImpl(
+				new String[] { "-startdb" });
+		assertTrue(options.getStartDatabase());
+		assertTrue(options.getStartDatabaseOnly());
+	}
+
+	@Test
+	public void workflowNameAndStartDB() throws Exception {
+		// should not throw an error
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-startdb", "myworkflow.t2flow" });
+		assertTrue(options.getStartDatabase());
+		assertFalse(options.getStartDatabaseOnly());
+	}
+
+	@Test(expected = InvalidOptionException.class)
+	public void provenanceButNoDatabase() throws Exception {
+		new CommandLineOptionsImpl(new String[] { "-provenance",
+				"myworkflow.t2flow" });
+	}
+
+	@Test(expected = InvalidOptionException.class)
+	public void provenanceButNoDatabase2() throws Exception {
+		new CommandLineOptionsImpl(new String[] { "-provenance", "-inmemory",
+				"myworkflow.t2flow" });
+	}
+
+	@Test
+	public void provenanceDatabase() throws Exception {
+		// should be no errors
+		new CommandLineOptionsImpl(new String[] { "-provenance", "-embedded",
+				"myworkflow.t2flow" });
+		new CommandLineOptionsImpl(new String[] { "-provenance", "-clientserver",
+				"myworkflow.t2flow" });
+		new CommandLineOptionsImpl(new String[] { "-provenance", "-dbproperties",
+				"dbproperties.properties", "myworkflow.t2flow" });
+	}
+
+	@Test
+	public void testHasInputDelimiter() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-inputvalue","in1","1,2,3","-inputdelimiter","in1",",","-inputdelimiter","in2",",","myworkflow.t2flow" });
+		assertTrue(options.hasDelimiterFor("in1"));
+		assertTrue(options.hasDelimiterFor("in2"));
+		assertFalse(options.hasDelimiterFor("in3"));
+	}
+
+	@Test(expected = InvalidOptionException.class)
+	public void testInputDelimiterInvalidWithInputDoc() throws Exception {
+		new CommandLineOptionsImpl(new String[] {
+				"-inputdoc","doc.xml","-inputdelimiter","in1",",","myworkflow.t2flow" });
+	}
+
+
+	@Test
+	public void testInputDelimiter() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-inputvalue","in1","1,2,3","-inputdelimiter","in1",",","-inputdelimiter","in2","!","myworkflow.t2flow" });
+		assertEquals(",",options.inputDelimiter("in1"));
+		assertEquals("!",options.inputDelimiter("in2"));
+		assertNull(options.inputDelimiter("in3"));
+	}
+
+	@Test
+	public void testInMemory() throws Exception {
+		CommandLineOptions handler = new CommandLineOptionsImpl(new String[] {
+				"-inmemory", "myworkflow.t2flow" });
+		assertTrue(handler.hasOption("inmemory"));
+	}
+
+	@Test
+	public void testEmbedded() throws Exception {
+		CommandLineOptions handler = new CommandLineOptionsImpl(new String[] {
+				"-embedded", "myworkflow.t2flow" });
+		assertTrue(handler.hasOption("embedded"));
+	}
+
+	@Test
+	public void testClientServer() throws Exception {
+		CommandLineOptions handler = new CommandLineOptionsImpl(new String[] {
+				"-clientserver", "myworkflow.t2flow" });
+		assertTrue(handler.hasOption("clientserver"));
+	}
+
+	@Test(expected = InvalidOptionException.class)
+	public void testInvalidEmbeddedAndClientServer() throws Exception {
+		new CommandLineOptionsImpl(new String[] { "-clientserver", "-embedded",
+				"myworkflow.t2flow" });
+	}
+
+	@Test(expected = InvalidOptionException.class)
+	public void testInvalidEmbeddedAndMemory() throws Exception {
+		new CommandLineOptionsImpl(new String[] { "-embedded", "-inmemory",
+				"myworkflow.t2flow" });
+	}
+
+	@Test(expected = InvalidOptionException.class)
+	public void testInvalidClientServerAndInMemory() throws Exception {
+		new CommandLineOptionsImpl(new String[] { "-clientserver", "-inmemory",
+				"myworkflow.t2flow" });
+	}
+
+	@Test
+	public void isInMemory() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-inmemory", "myworkflow.t2flow" });
+
+		assertTrue(options.isInMemory());
+		assertFalse(options.isClientServer());
+		assertFalse(options.isEmbedded());
+	}
+
+	@Test
+	public void isClientServer() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-clientserver", "myworkflow.t2flow" });
+
+		assertTrue(options.isClientServer());
+		assertFalse(options.isInMemory());
+		assertFalse(options.isEmbedded());
+	}
+
+	@Test
+	public void hasLogFile() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-logfile","/tmp/logging", "myworkflow.t2flow" });
+
+		assertTrue(options.hasLogFile());
+		assertEquals("/tmp/logging", options.getLogFile());
+	}
+
+	@Test(expected = InvalidOptionException.class)
+	@SuppressWarnings("unused")
+	public void hasLogFileNotValidWithoutWorkflow() throws Exception{
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-logfile","/tmp/logging"});
+	}
+
+	@Test
+	public void isEmbedded() throws Exception {
+		CommandLineOptions options = new CommandLineOptionsImpl(new String[] {
+				"-embedded", "myworkflow.t2flow" });
+
+		assertTrue(options.isEmbedded());
+		assertFalse(options.isInMemory());
+		assertFalse(options.isClientServer());
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/pom.xml b/taverna-commandline-product/pom.xml
new file mode 100644
index 0000000..38bcb42
--- /dev/null
+++ b/taverna-commandline-product/pom.xml
@@ -0,0 +1,529 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.commandline</groupId>
+		<artifactId>taverna-commandline</artifactId>
+		<version>3.1.0.incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-command-line-product</artifactId>
+	<name>Apache Taverna Commandline Product</name>
+	<packaging>taverna-application</packaging>
+	<profiles>
+		<profile>
+			<id>developer</id>
+			<activation>
+				<activeByDefault>true</activeByDefault>
+			</activation>
+			<properties>
+				<assembly.descriptor>src/main/assembly/developer-assembly.xml</assembly.descriptor>
+        <!-- See http://updates.taverna.org.uk/ -->
+				<profile.updateSite>https://taverna.incubator.apache.org/updates/commandline/</profile.updateSite>
+				<profile.pluginSite>https://taverna.incubator.apache.org/plugins/commandline/</profile.pluginSite>
+			</properties>
+		</profile>
+		<profile>
+			<id>nightly</id>
+			<properties>
+				<assembly.descriptor>src/main/assembly/nightly-assembly.xml</assembly.descriptor>
+				<profile.updateSite>https://taverna.incubator.apache.org/updates/commandline/</profile.updateSite>
+				<profile.pluginSite>https://taverna.incubator.apache.org/plugins/commandline/</profile.pluginSite>
+			</properties>
+		</profile>
+		<profile>
+			<id>release</id>
+			<properties>
+				<assembly.descriptor>src/main/assembly/release-assembly.xml</assembly.descriptor>
+				<profile.updateSite>https://taverna.incubator.apache.org/updates/commandline/</profile.updateSite>
+				<profile.pluginSite>https://taverna.incubator.apache.org/plugins/commandline/</profile.pluginSite>
+			</properties>
+		</profile>
+	</profiles>
+	<build>
+		<finalName>apache-taverna-commandline-${project.version}</finalName>
+		<plugins>
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<version>2.4</version>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<descriptors>
+						<descriptor>${assembly.descriptor}</descriptor>
+					</descriptors>
+					<archiverConfig>
+						<directoryMode>493</directoryMode> <!-- 493(dec) = 755(oct) -->
+						<defaultDirectoryMode>493</defaultDirectoryMode>
+					</archiverConfig>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>buildnumber-maven-plugin</artifactId>
+				<version>1.0-beta-3</version>
+				<executions>
+					<execution>
+						<id>buildnumber-validate</id>
+						<phase>validate</phase>
+						<goals>
+							<goal>create</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<format>{0,date,yyyyMMdd}T{0,date,HHmm}</format>
+					<items>
+						<item>timestamp</item>
+					</items>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.taverna.osgi</groupId>
+				<artifactId>taverna-maven-plugin</artifactId>
+				<version>${taverna.osgi.version}</version>
+				<extensions>true</extensions>
+				<configuration>
+					<buildNumber>${buildNumber}</buildNumber>
+					<updateSite>${profile.updateSite}</updateSite>
+					<pluginSite>${profile.pluginSite}</pluginSite>
+					<frameworkConfigurations>
+						<frameworkConfiguration>
+							<name>org.osgi.framework.bootdelegation</name>
+							<value>sun.*,com.sun.*,java.*,javax.*,org.xml.*,org.w3c.*,apple.*,com.apple.*,org.omg.*,org.ietf.jgss.*,org.jcp.xml.dsig.internal.*</value>
+						</frameworkConfiguration>
+						<frameworkConfiguration>
+							<name>org.osgi.framework.system.packages.extra</name>
+              <value>com.sun.org.apache.xml.internal.utils,com.sun.source.util,com.sun.source.tree,org.apache.log4j;version=${log4j.version},net.sf.taverna.t2.commandline.options;version=${project.parent.version}</value>
+						</frameworkConfiguration>
+						<frameworkConfiguration>
+							<name>org.osgi.framework.storage.clean</name>
+							<value>onFirstInit</value>
+						</frameworkConfiguration>
+					</frameworkConfigurations>
+				</configuration>
+			</plugin>
+		</plugins>
+		<pluginManagement>
+			<plugins>
+				<!--This plugin's configuration is used to store Eclipse m2e settings
+					only. It has no influence on the Maven build itself. -->
+				<plugin>
+					<groupId>org.eclipse.m2e</groupId>
+					<artifactId>lifecycle-mapping</artifactId>
+					<version>1.0.0</version>
+					<configuration>
+						<lifecycleMappingMetadata>
+							<pluginExecutions>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>org.apache.taverna.osgi</groupId>
+										<artifactId>taverna-maven-plugin</artifactId>
+										<versionRange>[0.3.1-SNAPSHOT,)</versionRange>
+										<goals>
+											<goal>profile-generate</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<execute>
+											<runOnIncremental>false</runOnIncremental>
+										</execute>
+									</action>
+								</pluginExecution>
+							</pluginExecutions>
+						</lifecycleMappingMetadata>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+
+	<dependencies>
+
+		<!-- Explicit org.osgi.* with <scope>provided as these are also provided
+			by the felix osgi package. Avoids: Caused by: java.lang.SecurityException:
+			class "org.osgi.framework.hooks.bundle.CollisionHook"'s signer information
+			does not match signer information of other classes in the same package -->
+
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.core</artifactId>
+			<version>${osgi.core.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.compendium</artifactId>
+			<version>${osgi.core.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+                <!-- Invalid manifest header Import-Package: "com.sun.jdmk.comm;resolution:="optional"" : Cannot import a package more than once "com.sun.jdmk.comm"-->
+		<dependency>
+			<groupId>log4j</groupId>
+			<artifactId>log4j</artifactId>
+			<version>${log4j.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<!-- Spring DM -->
+		<dependency>
+			<groupId>net.sourceforge.cglib</groupId>
+			<artifactId>com.springsource.net.sf.cglib</artifactId>
+			<version>${cglib.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.osgi</groupId>
+			<artifactId>spring-osgi-annotation</artifactId>
+			<version>${spring.dm.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.osgi</groupId>
+			<artifactId>spring-osgi-extender</artifactId>
+			<version>${spring.dm.version}</version>
+		</dependency>
+		<!-- Spring -->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>org.springframework.context</artifactId>
+			<version>${spring.version}</version>
+		</dependency>
+
+		<!-- Java Extension Implementations -->
+		<!-- Appears unrequired dependency>
+			<groupId>javax.xml.bind</groupId>
+			<artifactId>com.springsource.javax.xml.bind</artifactId>
+			<version>2.2.0</version>
+		</dependency-->
+		<dependency>
+			<groupId>javax.activation</groupId>
+			<artifactId>com.springsource.javax.activation</artifactId>
+			<version>${activation.version}</version>
+		</dependency>
+                <!-- The bundle "com.springsource.bsh_2.0.0.b4 " could not be resolved. Reason: Missing Constraint: Import-Package: javax.servlet; version="[2.5.0,3.0.0)" -->
+		<dependency>
+ 			<groupId>javax.servlet</groupId>
+			<artifactId>com.springsource.javax.servlet</artifactId>
+			<version>2.5.0</version>
+		</dependency>
+                <!-- The bundle "com.springsource.org.apache.axis_1.4.0 " could not be resolved. Reason: Missing Constraint: Import-Package: javax.jms; version="[1.1.0,2.0.0)" -->
+		<dependency>
+			<groupId>javax.jms</groupId>
+			<artifactId>com.springsource.javax.jms</artifactId>
+			<version>1.1.0</version>
+		</dependency>
+                <!-- The bundle "com.springsource.javax.xml.rpc_1.1.0 " could not be resolved. Reason: Missing Constraint: Import-Package: javax.xml.soap; version="[1.3.0,2.0.0)" -->
+		<dependency>
+			<groupId>javax.xml.soap</groupId>
+			<artifactId>com.springsource.javax.xml.soap</artifactId>
+			<version>1.3.0</version>
+		</dependency>
+                <!-- The bundle "com.springsource.com.thoughtworks.xstream_1.4.1" could not be resolved. Reason: Missing Constraint: Import-Package: javax.xml.stream; version="[1.0.1,2.0.0)" -->
+		<dependency>
+			<groupId>javax.xml.stream</groupId>
+			<artifactId>com.springsource.javax.xml.stream</artifactId>
+			<version>1.0.1</version>
+		</dependency>
+		<dependency>
+			<groupId>javax.mail</groupId>
+			<artifactId>com.springsource.javax.mail</artifactId>
+			<version>${mail.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+			<version>${commons.codec.version}</version>
+		</dependency>
+  <dependency>
+    <groupId>commons-configuration</groupId>
+    <artifactId>commons-configuration</artifactId>
+    <version>1.10</version>
+  </dependency>
+  <dependency>
+      <groupId>com.sun.xml.bind</groupId>
+      <artifactId>jaxb-impl</artifactId>
+      <version>2.2.11</version>
+  </dependency>
+
+
+		<!-- OSGi Enterprise Services -->
+		<dependency>
+			<groupId>org.apache.taverna.osgi</groupId>
+			<artifactId>xml-parser-service</artifactId>
+			<version>${taverna.osgi.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.osgi</groupId>
+			<artifactId>xml-transformer-service</artifactId>
+			<version>${taverna.osgi.version}</version>
+		</dependency>
+                <!-- The bundle "uk.org.taverna.commons.taverna-plugin-impl_0.1.0.SNAPSHOT" could not be resolved. Reason: Missing Constraint: Import-Package: org.osgi.service.event; version="[1.3.0,2.0.0)" -->
+		<dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.apache.felix.eventadmin</artifactId>
+			<version>1.3.2</version>
+		</dependency>
+		<!-- Appears unrequired dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.apache.felix.configadmin</artifactId>
+			<version>1.6.0</version>
+		</dependency-->
+
+		<!-- Taverna Activities -->
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-dataflow-activity</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-stringconstant-activity</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+
+    <!-- Taverna Common Activities -->
+    <dependency>
+			<groupId>org.apache.taverna.commonactivities</groupId>
+      <artifactId>taverna-beanshell-activity</artifactId>
+			<version>${taverna.commonactivities.version}</version>
+    </dependency>
+    <dependency>
+			<groupId>org.apache.taverna.commonactivities</groupId>
+      <artifactId>taverna-external-tool-activity</artifactId>
+			<version>${taverna.commonactivities.version}</version>
+    </dependency>
+    <!-- VERY broken :(
+    <dependency>
+			<groupId>org.apache.taverna.commonactivities</groupId>
+      <artifactId>taverna-interaction-activity</artifactId>
+			<version>${taverna.commonactivities.version}</version>
+    </dependency>
+    -->
+    <dependency>
+			<groupId>org.apache.taverna.commonactivities</groupId>
+      <artifactId>taverna-rest-activity</artifactId>
+			<version>${taverna.commonactivities.version}</version>
+    </dependency>
+    <dependency>
+			<groupId>org.apache.taverna.commonactivities</groupId>
+      <artifactId>taverna-spreadsheet-import-activity</artifactId>
+			<version>${taverna.commonactivities.version}</version>
+    </dependency>
+    <dependency>
+			<groupId>org.apache.taverna.commonactivities</groupId>
+      <artifactId>taverna-wsdl-activity</artifactId>
+			<version>${taverna.commonactivities.version}</version>
+    </dependency>
+    <dependency>
+			<groupId>org.apache.taverna.commonactivities</groupId>
+      <artifactId>taverna-xpath-activity</artifactId>
+			<version>${taverna.commonactivities.version}</version>
+    </dependency>
+
+
+		<!-- Taverna Commandline -->
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-commandline-common</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-commandline-launcher</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+
+		<!-- Taverna Platform -->
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-capability-impl</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-run-impl</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-execution-impl</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-execution-local</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-database-configuration-impl</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-services-impl</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+
+		<!-- Taverna OSGi -->
+		<dependency>
+			<groupId>org.apache.taverna.osgi</groupId>
+			<artifactId>taverna-configuration-impl</artifactId>
+			<version>${taverna.osgi.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.osgi</groupId>
+			<artifactId>taverna-app-configuration-impl</artifactId>
+			<version>${taverna.osgi.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.osgi</groupId>
+			<artifactId>taverna-download-impl</artifactId>
+			<version>${taverna.osgi.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.osgi</groupId>
+			<artifactId>taverna-plugin-impl</artifactId>
+			<version>${taverna.osgi.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.osgi</groupId>
+			<artifactId>taverna-update-impl</artifactId>
+			<version>${taverna.osgi.version}</version>
+		</dependency>
+
+		<!-- Scufl2 -->
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-rdfxml</artifactId>
+			<version>${taverna.language.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-t2flow</artifactId>
+			<version>${taverna.language.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-validation-structural</artifactId>
+			<version>${taverna.language.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-validation-correctness</artifactId>
+			<version>${taverna.language.version}</version>
+		</dependency>
+
+		<!-- Data bundle -->
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-databundle</artifactId>
+			<version>${taverna.language.version}</version>
+		</dependency>
+		<!-- HTTP client needed by Data Bundle -->
+		<!-- Appears unrequired dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient-osgi</artifactId>
+			<version>4.2.5</version>
+		</dependency-->
+		<!-- Appears unrequired dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpcore-osgi</artifactId>
+			<version>4.2.5</version>
+		</dependency-->
+		<!-- Jena bundle needed by jsonld-java-jena -->
+		<!-- See https://github.com/stain/jena/tree/jena-bundle/jena-bundle -->
+		<dependency>
+			<groupId>org.apache.jena</groupId>
+			<artifactId>jena-osgi</artifactId>
+			<version>2.12.2-SNAPSHOT</version>
+		</dependency>
+		<!-- slf4j implementation -->
+                <!-- The bundle "org.purl.wf4ever.robundle_0.3.1 " could not be resolved. Reason: Missing Constraint: Import-Package: org.slf4j; version="[1.7.0,2.0.0)"-->
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+      <version>${slf4j.version}</version>
+		</dependency>
+
+    <!-- Appears unrequired: -->
+    <dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+      <version>${slf4j.version}</version>
+		</dependency>
+
+		<!-- Taverna Security -->
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-credential-manager-impl</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+
+		<!-- Taverna Workflow Engine -->
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-workflowmodel-impl</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-workflowmodel-core-extensions</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-reference-impl</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-reference-types</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+
+		<!-- Taverna Provenance -->
+		<!--dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>provenance-derby</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>provenance-mysql</artifactId>
+			<version>${taverna.engine.version}</version>
+		</dependency-->
+                <!-- The bundle "org.purl.wf4ever.robundle_0.3.1 " could not be resolved. Reason: Missing Constraint: Import-Package: com.fasterxml.jackson.annotation; version="[2.3.0,3.0.0)"-->
+		<dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.3.0</version>
+    </dependency>
+		<dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <version>2.3.0</version>
+    </dependency>
+		<dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.3.0</version>
+    </dependency>
+
+    <dependency>
+      <groupId>nu.validator.htmlparser</groupId>
+      <artifactId>htmlparser</artifactId>
+      <version>${htmlparser.version}</version>
+    </dependency>
+
+
+
+	</dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/src/main/assembly/dependencies-component.xml
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/src/main/assembly/dependencies-component.xml b/taverna-commandline-product/src/main/assembly/dependencies-component.xml
new file mode 100644
index 0000000..0e8640e
--- /dev/null
+++ b/taverna-commandline-product/src/main/assembly/dependencies-component.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component
+	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/component/1.1.2"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/component/1.1.2 http://maven.apache.org/xsd/component-1.1.2.xsd">
+
+	<fileSets>
+		<fileSet>
+			<directory>src/main/etc</directory>
+			<fileMode>0755</fileMode>
+			<outputDirectory></outputDirectory>
+			<filtered>true</filtered>
+		</fileSet>
+		<fileSet>
+			<directory>${project.build.directory}/taverna-tmp</directory>
+			<fileMode>0755</fileMode>
+			<outputDirectory></outputDirectory>
+		</fileSet>
+	</fileSets>
+
+</component>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/src/main/assembly/developer-assembly.xml
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/src/main/assembly/developer-assembly.xml b/taverna-commandline-product/src/main/assembly/developer-assembly.xml
new file mode 100644
index 0000000..ae2a7c3
--- /dev/null
+++ b/taverna-commandline-product/src/main/assembly/developer-assembly.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly
+	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+	<id>dev</id>
+	<formats>
+		<format>dir</format>
+	</formats>
+	<componentDescriptors>
+		<componentDescriptor>dependencies-component.xml</componentDescriptor>
+	</componentDescriptors>
+</assembly>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/src/main/assembly/nightly-assembly.xml
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/src/main/assembly/nightly-assembly.xml b/taverna-commandline-product/src/main/assembly/nightly-assembly.xml
new file mode 100644
index 0000000..f82e793
--- /dev/null
+++ b/taverna-commandline-product/src/main/assembly/nightly-assembly.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly
+	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+	<id>nightly</id>
+	<baseDirectory>taverna-command-line-${project.version}-${buildNumber}-nightly</baseDirectory>
+	<formats>
+		<!-- <format>dir</format> -->
+		<format>zip</format>
+	</formats>
+	<componentDescriptors>
+		<componentDescriptor>dependencies-component.xml</componentDescriptor>
+	</componentDescriptors>
+</assembly>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/src/main/assembly/release-assembly.xml
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/src/main/assembly/release-assembly.xml b/taverna-commandline-product/src/main/assembly/release-assembly.xml
new file mode 100644
index 0000000..61da752
--- /dev/null
+++ b/taverna-commandline-product/src/main/assembly/release-assembly.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly
+	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+	<id>release</id>
+	<baseDirectory>taverna-command-line-${project.version}</baseDirectory>
+	<formats>
+		<!-- <format>dir</format> -->
+		<format>zip</format>
+	</formats>
+	<componentDescriptors>
+		<componentDescriptor>dependencies-component.xml</componentDescriptor>
+	</componentDescriptors>
+</assembly>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/src/main/etc/conf/log4j.properties
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/src/main/etc/conf/log4j.properties b/taverna-commandline-product/src/main/etc/conf/log4j.properties
new file mode 100644
index 0000000..5014f2b
--- /dev/null
+++ b/taverna-commandline-product/src/main/etc/conf/log4j.properties
@@ -0,0 +1,14 @@
+# By default, WARN (our external libraries)
+log4j.rootLogger=INFO, CONSOLE
+
+# Get rid of some xml sec warnings
+log4j.logger.org.apache.ws.security=ERROR
+log4j.logger.org.apache.commons.httpclient=ERROR
+
+# Default output to console is restrictive
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%-5p %d{ISO8601} (%c:%L) - %m%n
+
+# Output WARN and above to console -
+log4j.appender.CONSOLE.Threshold=ERROR
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/src/main/etc/conf/logging.properties
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/src/main/etc/conf/logging.properties b/taverna-commandline-product/src/main/etc/conf/logging.properties
new file mode 100644
index 0000000..b03a43f
--- /dev/null
+++ b/taverna-commandline-product/src/main/etc/conf/logging.properties
@@ -0,0 +1,10 @@
+handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
+
+.level = ALL
+
+java.util.logging.ConsoleHandler.level = WARNING
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+java.util.logging.FileHandler.level = ALL
+java.util.logging.FileHandler.count = 5
+java.util.logging.FileHandler.limit = 1048576

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/src/main/etc/conf/taverna.app.properties
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/src/main/etc/conf/taverna.app.properties b/taverna-commandline-product/src/main/etc/conf/taverna.app.properties
new file mode 100644
index 0000000..91522d4
--- /dev/null
+++ b/taverna-commandline-product/src/main/etc/conf/taverna.app.properties
@@ -0,0 +1,2 @@
+taverna.app.name=taverna-cl-3.0.0
+taverna.app.title=Taverna Command Line 3.0.0

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/src/main/etc/executeworkflow.bat
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/src/main/etc/executeworkflow.bat b/taverna-commandline-product/src/main/etc/executeworkflow.bat
new file mode 100644
index 0000000..2e18831
--- /dev/null
+++ b/taverna-commandline-product/src/main/etc/executeworkflow.bat
@@ -0,0 +1,17 @@
+@ECHO OFF
+
+REM Taverna startup script
+
+REM distribution directory
+set TAVERNA_HOME=%~dp0
+
+
+REM 1 GB memory, 400 MB for classes
+set ARGS=-Xmx1g -XX:MaxPermSize=400m
+
+REM Taverna system properties
+set ARGS=%ARGS% "-Dlog4j.configuration=file:///%TAVERNA_HOME%conf/log4j.properties"
+set ARGS=%ARGS% "-Djava.util.logging.config.file=%TAVERNA_HOME%conf/logging.properties"
+set ARGS=%ARGS% "-Dtaverna.app.startup=%TAVERNA_HOME%."
+
+java %ARGS% -jar "%TAVERNA_HOME%lib\/lib/org.apache.taverna.commandline/taverna-commandline-launcher-3.1.0.incubating-SNAPSHOT.jar" %*

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-product/src/main/etc/executeworkflow.sh
----------------------------------------------------------------------
diff --git a/taverna-commandline-product/src/main/etc/executeworkflow.sh b/taverna-commandline-product/src/main/etc/executeworkflow.sh
new file mode 100644
index 0000000..5ef0916
--- /dev/null
+++ b/taverna-commandline-product/src/main/etc/executeworkflow.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+set -e
+
+## resolve links - $0 may be a symlink
+prog="$0"
+
+real_path() {
+    readlink -m "$1" 2>/dev/null || python -c 'import os,sys;print os.path.realpath(sys.argv[1])' "$1"
+}
+
+realprog=`real_path "$prog"`
+taverna_home=`dirname "$realprog"`
+javabin=java
+if test -x "$JAVA_HOME/bin/java"; then
+    javabin="$JAVA_HOME/bin/java"
+fi
+
+# 1 GB memory, 400 MB for classes
+exec "$javabin" -Xmx1g -XX:MaxPermSize=400m \
+  "-Dlog4j.configuration=file://$taverna_home/conf/log4j.properties " \
+  "-Djava.util.logging.config.file=$taverna_home/conf/logging.properties " \
+  "-Dtaverna.app.startup=$taverna_home" \
+  -jar "$taverna_home/lib/org.apache.taverna.commandline/taverna-commandline-launcher-3.1.0.incubating-SNAPSHOT.jar" \
+  ${1+"$@"}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-commandline/blob/53c8a6c1/taverna-commandline-tests/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-commandline-tests/pom.xml b/taverna-commandline-tests/pom.xml
new file mode 100644
index 0000000..e28c4a0
--- /dev/null
+++ b/taverna-commandline-tests/pom.xml
@@ -0,0 +1,71 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.commandline</groupId>
+		<artifactId>taverna-commandline</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-command-line-tests</artifactId>
+	<name>Apache Taverna Commandline Tests</name>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<version>2.12</version>
+				<configuration>
+					<systemPropertyVariables>
+						<buildDirectory>${project.build.directory}</buildDirectory>
+					</systemPropertyVariables>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-t2flow</artifactId>
+			<version>${taverna.language.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-rdfxml</artifactId>
+			<version>${taverna.language.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.8.1</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>2.2</version>
+			<scope>test</scope>
+		</dependency>
+		<!-- Optional for scufl2-xdfxml -->
+		<dependency>
+			<groupId>com.sun.xml.bind</groupId>
+			<artifactId>jaxb-impl</artifactId>
+			<version>2.2.4-1</version>
+			<scope>test</scope>
+		</dependency>
+		<!-- Required by scufl2-xdfxml, see SCUFL2-122 -->
+		<dependency>
+			<groupId>org.jdom</groupId>
+			<artifactId>com.springsource.org.jdom</artifactId>
+			<version>1.1.0</version>
+			<scope>test</scope>
+		</dependency>
+		<!-- <dependency>
+			<groupId>org.jdom</groupId>
+			<artifactId>jdom</artifactId>
+			<version>1.1.2</version>
+			<scope>test</scope>
+		</dependency> -->
+	</dependencies>
+</project>