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 16:37:22 UTC

[22/49] incubator-taverna-server git commit: taverna-* module names

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-execution-delegate/src/test/java/SerializationTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-execution-delegate/src/test/java/SerializationTest.java b/taverna-server-execution-delegate/src/test/java/SerializationTest.java
new file mode 100644
index 0000000..c4bf0b9
--- /dev/null
+++ b/taverna-server-execution-delegate/src/test/java/SerializationTest.java
@@ -0,0 +1,54 @@
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.taverna.server.execution_delegate.RemoteExecution.WorkflowReportDocument;
+
+public class SerializationTest {
+	private static final boolean PRINT = true;
+	SchemaOutputResolver sink;
+	StringWriter schema;
+
+	String schema() {
+		return schema.toString();
+	}
+
+	@Before
+	public void init() {
+		schema = new StringWriter();
+		sink = new SchemaOutputResolver() {
+			@Override
+			public Result createOutput(String namespaceUri,
+					String suggestedFileName) throws IOException {
+				StreamResult sr = new StreamResult(schema);
+				sr.setSystemId("/dev/null");
+				return sr;
+			}
+		};
+		assertEquals("", schema());
+	}
+
+	@Test
+	public void testSchemaGeneration() throws JAXBException, IOException {
+		JAXBContext.newInstance(WorkflowReportDocument.class).generateSchema(
+				sink);
+		assertFalse("generated schema must be non-empty", schema().isEmpty());
+		assertTrue(
+				"generated schema must define workflowReport element",
+				schema().contains(
+						"<xs:element name=\"workflowReport\" type=\"WorkflowReport\"/>\n"));
+		if (PRINT)
+			System.out.print(schema());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/.gitignore
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/.gitignore b/taverna-server-port-description/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/taverna-server-port-description/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/pom.xml b/taverna-server-port-description/pom.xml
new file mode 100644
index 0000000..99582ed
--- /dev/null
+++ b/taverna-server-port-description/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project 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.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-port-description</artifactId>
+	<name>Apache Taverna Server Workflow Port Descriptor Types</name>
+	<description>The structural types used to describe ports on workflows, as exported by Taverna Server.</description>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+	<build>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-eclipse-plugin</artifactId>
+					<configuration>
+						<projectNameTemplate>[artifactId]-[version]</projectNameTemplate>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
new file mode 100644
index 0000000..2ea392f
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(name = "AbsentValue")
+public class AbsentValue extends AbstractValue {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
new file mode 100644
index 0000000..e57c4f9
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlID;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.taverna.server.port_description.utils.IntAdapter;
+
+@XmlType(name = "Port")
+public class AbstractPort {
+	@XmlID
+	@XmlAttribute(required = true)
+	public String name;
+
+	@XmlAttribute
+	@XmlSchemaType(name = "int")
+	@XmlJavaTypeAdapter(IntAdapter.class)
+	public Integer depth;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
new file mode 100644
index 0000000..7c3fe9a
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(name = "PortDescription")
+public abstract class AbstractPortDescription {
+	@XmlAttribute
+	public String workflowId;
+	@XmlAttribute
+	@XmlSchemaType(name = "anyURI")
+	public URI workflowRun;
+	@XmlAttribute
+	public String workflowRunId;
+
+	public void fillInBaseData(String docId, String runId, URI runUrl) {
+		this.workflowId = docId;
+		this.workflowRun = runUrl;
+		this.workflowRunId = runId;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
new file mode 100644
index 0000000..47232c2
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import static org.taverna.server.port_description.Namespaces.XLINK;
+
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(name = "Value")
+@XmlSeeAlso( { ErrorValue.class, LeafValue.class, ListValue.class, AbsentValue.class })
+public abstract class AbstractValue {
+	@XmlAttribute(namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI href;
+
+	public void setAddress(URI uri, String localAddress) {
+		if (uri.getPath().endsWith("/")) {
+			href = URI.create(uri + "wd/out/" + localAddress);
+		} else {
+			href = URI.create(uri + "/wd/out/" + localAddress);
+		}
+		//about = "out/" + localAddress;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
new file mode 100644
index 0000000..0bb07b4
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.taverna.server.port_description.utils.IntAdapter;
+
+@XmlType(name = "ErrorValue")
+public class ErrorValue extends AbstractValue {
+	@XmlAttribute
+	@XmlSchemaType(name = "int")
+	@XmlJavaTypeAdapter(IntAdapter.class)
+	public Integer depth;
+	@XmlAttribute(name = "errorFile")
+	public String fileName;
+	@XmlAttribute(name = "errorByteLength")
+	public Long byteLength;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
new file mode 100644
index 0000000..60b9353
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import static org.taverna.server.port_description.Namespaces.XLINK;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * A description of the inputs of a workflow run, as they are currently known
+ * about.
+ * 
+ * @author Donal Fellows.
+ */
+@XmlRootElement
+public class InputDescription extends AbstractPortDescription {
+	@XmlElement
+	public List<InputPort> input = new ArrayList<>();
+
+	@XmlType(name = "InputPort")
+	public static class InputPort extends AbstractPort {
+		@XmlAttribute(namespace = XLINK)
+		@XmlSchemaType(name = "anyURI")
+		public URI href;
+	}
+
+	/**
+	 * Add an input port to the list of ports.
+	 * 
+	 * @param name
+	 *            The name of the port to add.
+	 * @return The port (so that its details may be set);
+	 */
+	public InputPort addPort(String name) {
+		InputPort p = new InputPort();
+		p.name = name;
+		input.add(p);
+		return p;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
new file mode 100644
index 0000000..052c0ef
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(name = "LeafValue")
+public class LeafValue extends AbstractValue {
+	@XmlAttribute(name = "contentFile")
+	public String fileName;
+	@XmlAttribute(name = "contentType")
+	public String contentType;
+	@XmlAttribute(name = "contentByteLength")
+	public Long byteLength;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
new file mode 100644
index 0000000..b14cdf1
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.taverna.server.port_description.utils.IntAdapter;
+
+@XmlType(name = "ListValue")
+public class ListValue extends AbstractValue {
+	@XmlAttribute
+	@XmlSchemaType(name = "int")
+	@XmlJavaTypeAdapter(IntAdapter.class)
+	public Integer length;
+	@XmlElements({
+			@XmlElement(name = "value", type = LeafValue.class, nillable = false),
+			@XmlElement(name = "list", type = ListValue.class, nillable = false),
+			@XmlElement(name = "error", type = ErrorValue.class, nillable = false),
+			@XmlElement(name = "absent", type = AbsentValue.class, nillable = false) })
+	public List<AbstractValue> contents = new ArrayList<>();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
new file mode 100644
index 0000000..4003cdb
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+public interface Namespaces {
+	static final String DATA = "http://ns.taverna.org.uk/2010/port/";
+	static final String RUN = "http://ns.taverna.org.uk/2010/run/";
+	static final String XLINK = "http://www.w3.org/1999/xlink";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
new file mode 100644
index 0000000..0b94973
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * A description of the outputs of a workflow run, as they are currently known
+ * about.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement(name = "workflowOutputs")
+public class OutputDescription extends AbstractPortDescription {
+	private static final AbsentValue ABSENT_VALUE = new AbsentValue();
+	@XmlElement(name = "output")
+	public List<OutputPort> ports = new ArrayList<>();
+
+	@XmlType(name = "OutputPort")
+	public static class OutputPort extends AbstractPort {
+		@XmlElements({
+				@XmlElement(name = "value", type = LeafValue.class, nillable = false, required = true),
+				@XmlElement(name = "list", type = ListValue.class, nillable = false, required = true),
+				@XmlElement(name = "error", type = ErrorValue.class, nillable = false, required = true),
+				@XmlElement(name = "absent", type = AbsentValue.class, nillable = false, required = true) })
+		public AbstractValue output;
+	}
+
+	/**
+	 * Add an output port to the list of ports.
+	 * 
+	 * @param name
+	 *            The name of the port to add.
+	 * @return The port (so that its value may be set);
+	 */
+	public OutputPort addPort(String name) {
+		OutputPort p = new OutputPort();
+		p.name = name;
+		p.output = ABSENT_VALUE;
+		ports.add(p);
+		return p;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
new file mode 100644
index 0000000..b1ac2c6
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+@XmlSchema(namespace = DATA, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "port", namespaceURI = DATA),
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "run", namespaceURI = RUN) })
+package org.taverna.server.port_description;
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.port_description.Namespaces.DATA;
+import static org.taverna.server.port_description.Namespaces.RUN;
+import static org.taverna.server.port_description.Namespaces.XLINK;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
new file mode 100644
index 0000000..8764176
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description.utils;
+
+import static javax.xml.bind.DatatypeConverter.parseInt;
+import static javax.xml.bind.DatatypeConverter.printInt;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * A type conversion utility for use with JAXB.
+ * 
+ * @author Donal Fellows
+ */
+public class IntAdapter extends XmlAdapter<String, Integer> {
+	@Override
+	public String marshal(Integer value) throws Exception {
+		if (value == null)
+			return null;
+		return printInt(value);
+	}
+
+	@Override
+	public Integer unmarshal(String value) throws Exception {
+		if (value == null)
+			return null;
+		return parseInt(value);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java b/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
new file mode 100644
index 0000000..c952ec2
--- /dev/null
+++ b/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
@@ -0,0 +1,98 @@
+package org.taverna.server.port_description;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This test file ensures that the JAXB bindings will work once deployed instead
+ * of mysteriously failing in service.
+ * 
+ * @author Donal Fellows
+ */
+public class JaxbSanityTest {
+	SchemaOutputResolver sink;
+	StringWriter schema;
+
+	String schema() {
+		return schema.toString();
+	}
+
+	private String schemaTest(Class<?>... classes) throws IOException, JAXBException {
+		Assert.assertTrue(schema().isEmpty());
+		JAXBContext.newInstance(classes).generateSchema(sink);
+		Assert.assertFalse(schema().isEmpty());
+		return schema();
+	}
+
+	@Before
+	public void init() {
+		schema = new StringWriter();
+		sink = new SchemaOutputResolver() {
+			@Override
+			public Result createOutput(String namespaceUri,
+					String suggestedFileName) throws IOException {
+				StreamResult sr = new StreamResult(schema);
+				sr.setSystemId("/dev/null");
+				return sr;
+			}
+		};
+	}
+
+	@Test
+	public void testJAXBForInput() throws Exception {
+		schemaTest(InputDescription.InputPort.class);
+	}
+
+	@Test
+	public void testJAXBForInputDescription() throws Exception {
+		schemaTest(InputDescription.class);
+	}
+
+	@Test
+	public void testJAXBForAbsentValue() throws Exception {
+		schemaTest(AbstractValue.class);
+	}
+
+	@Test
+	public void testJAXBForAbstractValue() throws Exception {
+		schemaTest(AbstractValue.class);
+	}
+
+	@Test
+	public void testJAXBForErrorValue() throws Exception {
+		schemaTest(ErrorValue.class);
+	}
+
+	@Test
+	public void testJAXBForLeafValue() throws Exception {
+		schemaTest(LeafValue.class);
+	}
+
+	@Test
+	public void testJAXBForListValue() throws Exception {
+		schemaTest(ListValue.class);
+	}
+
+	@Test
+	public void testJAXBForOutputDescription() throws Exception {
+		schemaTest(OutputDescription.class);
+	}
+
+	@Test
+	public void testJAXBForEverythingAtOnce() throws Exception {
+		schemaTest(AbsentValue.class, AbstractValue.class, ListValue.class,
+				LeafValue.class, ErrorValue.class, OutputDescription.class,
+				InputDescription.InputPort.class, InputDescription.class);
+		// System.out.println(schema());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-rmidaemon/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/pom.xml b/taverna-server-rmidaemon/pom.xml
new file mode 100644
index 0000000..0e2a565
--- /dev/null
+++ b/taverna-server-rmidaemon/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project 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.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>taverna-server-rmidaemon</artifactId>
+	<name>Apache Taverna Server RMI registry daemon</name>
+	<description>Customised RMI registry that supports restricting to localhost.</description>
+
+	<properties>
+		<project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
+		<mainClass>org.taverna.server.rmidaemon.Registry</mainClass>
+	</properties>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<descriptorRefs>
+						<descriptorRef>jar-with-dependencies</descriptorRef>
+					</descriptorRefs>
+					<archive>
+						<manifest>
+							<mainClass>${mainClass}</mainClass>
+						</manifest>
+					</archive>
+				</configuration>
+				<executions>
+					<execution>
+						<id>make-assembly</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
new file mode 100644
index 0000000..4be7579
--- /dev/null
+++ b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
@@ -0,0 +1,72 @@
+package org.taverna.server.rmidaemon;
+
+import static java.lang.System.setProperty;
+import static java.net.InetAddress.getLocalHost;
+import static java.rmi.registry.LocateRegistry.createRegistry;
+import static java.rmi.registry.Registry.REGISTRY_PORT;
+import static java.rmi.server.RMISocketFactory.getDefaultSocketFactory;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.net.ServerSocket;
+import java.rmi.MarshalledObject;
+import java.rmi.server.RMIServerSocketFactory;
+
+/**
+ * Special version of <tt>rmiregistry</tt>.
+ * 
+ * @author Donal Fellows
+ */
+public class Registry {
+	/**
+	 * Run a registry. The first optional argument is the port for the registry
+	 * to listen on, and the second optional argument is whether the registry
+	 * should restrict itself to connections from localhost only.
+	 * 
+	 * @param args
+	 *            Arguments to the program.
+	 */
+	public static void main(String... args) {
+		try {
+			if (args.length > 0)
+				port = Integer.parseInt(args[0]);
+		} catch (Exception e) {
+			System.err.println("failed to parse port: " + e.getMessage());
+			System.exit(2);
+		}
+		try {
+			if (args.length > 1)
+				localhostOnly = Boolean.parseBoolean(args[1]);
+		} catch (Exception e) {
+			System.err.println("failed to parse boolean localhost flag: "
+					+ e.getMessage());
+			System.exit(2);
+		}
+		try {
+			Object registryHandle = makeRegistry();
+			try (ObjectOutputStream oos = new ObjectOutputStream(System.out)) {
+				oos.writeObject(registryHandle);
+			}
+		} catch (Exception e) {
+			System.err.println("problem creating registry: " + e.getMessage());
+			System.exit(1);
+		}
+	}
+
+	private static int port = REGISTRY_PORT;
+	private static boolean localhostOnly = false;
+
+	private static MarshalledObject<java.rmi.registry.Registry> makeRegistry() throws IOException {
+		if (!localhostOnly)
+			return new MarshalledObject<>(createRegistry(port));
+		setProperty("java.rmi.server.hostname", "127.0.0.1");
+		return new MarshalledObject<>(createRegistry(port,
+				getDefaultSocketFactory(), new RMIServerSocketFactory() {
+					@Override
+					public ServerSocket createServerSocket(int port)
+							throws IOException {
+						return new ServerSocket(port, 0, getLocalHost());
+					}
+				}));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
new file mode 100644
index 0000000..32144b5
--- /dev/null
+++ b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * RMI daemon implementation. A variation of an RMI registry.
+ * @author Donal Fellows
+ */
+package org.taverna.server.rmidaemon;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/.gitignore
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/.gitignore b/taverna-server-runinterface/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/taverna-server-runinterface/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/pom.xml b/taverna-server-runinterface/pom.xml
new file mode 100644
index 0000000..efd3763
--- /dev/null
+++ b/taverna-server-runinterface/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project 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.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>taverna-server-runinterface</artifactId>
+	<name>Apache Taverna Server RMI Interface: Webapp &lt;-&gt; Worker</name>
+	<description>This is the implementation of the RMI interface between the workflow run factory and the web-app service front-end.</description>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF b/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5e94951
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
new file mode 100644
index 0000000..9f4bf50
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that indicates where a change of a workflow run's status is
+ * illegal.
+ * 
+ * @author Donal Fellows
+ * @see RemoteSingleRun#setStatus(RemoteStatus)
+ */
+@WebFault(name = "IllegalStateTransitionFault", targetNamespace = "http://ns.taverna.org.uk/2010/xml/server/worker/")
+public class IllegalStateTransitionException extends Exception {
+	private static final long serialVersionUID = 159673249162345L;
+
+	public IllegalStateTransitionException() {
+		this("illegal state transition");
+	}
+
+	public IllegalStateTransitionException(String message) {
+		super(message);
+	}
+
+	public IllegalStateTransitionException(Throwable cause) {
+		this("illegal state transition", cause);
+	}
+
+	public IllegalStateTransitionException(String message, Throwable cause) {
+		super(message, cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
new file mode 100644
index 0000000..a47d112
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that indicates that the implementation has gone wrong in some
+ * unexpected way.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "ImplementationFault", targetNamespace = "http://ns.taverna.org.uk/2010/xml/server/worker/")
+@SuppressWarnings("serial")
+public class ImplementationException extends Exception {
+	public ImplementationException(String message) {
+		super(message);
+	}
+
+	public ImplementationException(String message, Throwable cause) {
+		super(message, cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
new file mode 100644
index 0000000..395842a
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Represents a directory that is the working directory of a workflow run, or a
+ * sub-directory of it.
+ * 
+ * @author Donal Fellows
+ * @see RemoteFile
+ */
+public interface RemoteDirectory extends RemoteDirectoryEntry {
+	/**
+	 * @return A list of the contents of the directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If anything goes wrong with listing the directory.
+	 */
+	@Nonnull
+	public Collection<RemoteDirectoryEntry> getContents()
+			throws RemoteException, IOException;
+
+	/**
+	 * Creates a sub-directory of this directory.
+	 * 
+	 * @param name
+	 *            The name of the sub-directory.
+	 * @return A handle to the newly-created directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong with creating the subdirectory.
+	 */
+	@Nonnull
+	public RemoteDirectory makeSubdirectory(@Nonnull String name)
+			throws RemoteException, IOException;
+
+	/**
+	 * Creates an empty file in this directory.
+	 * 
+	 * @param name
+	 *            The name of the file to create.
+	 * @return A handle to the newly-created file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If anything goes wrong with creating the file.
+	 */
+	@Nonnull
+	public RemoteFile makeEmptyFile(@Nonnull String name)
+			throws RemoteException, IOException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
new file mode 100644
index 0000000..1e04b44
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.io.IOException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Date;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * An entry in a {@link RemoteDirectory} representing a file or sub-directory.
+ * 
+ * @author Donal Fellows
+ * @see RemoteDirectory
+ * @see RemoteFile
+ */
+public interface RemoteDirectoryEntry extends Remote {
+	/**
+	 * @return The "local" name of the entry. This will never be "<tt>..</tt>"
+	 *         or contain the character "<tt>/</tt>".
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getName() throws RemoteException;
+
+	/**
+	 * @return The time when the entry was last modified.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public Date getModificationDate() throws RemoteException;
+
+	/**
+	 * Gets the directory containing this directory entry.
+	 * 
+	 * @return A directory handle, or <tt>null</tt> if called on the workflow
+	 *         run's working directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public RemoteDirectory getContainingDirectory() throws RemoteException;
+
+	/**
+	 * Destroy this directory entry, deleting the file or sub-directory. The
+	 * workflow run's working directory can never be manually destroyed.
+	 * 
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong when deleting the directory entry.
+	 */
+	public void destroy() throws RemoteException, IOException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
new file mode 100644
index 0000000..e09466d
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.io.IOException;
+import java.rmi.RemoteException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Represents a file in the working directory of a workflow instance run, or in
+ * some sub-directory of it.
+ * 
+ * @author Donal Fellows
+ * @see RemoteDirectory
+ */
+public interface RemoteFile extends RemoteDirectoryEntry {
+	/**
+	 * Read from the file.
+	 * 
+	 * @param offset
+	 *            Where in the file to read the bytes from.
+	 * @param length
+	 *            How much of the file to read; -1 for "to the end".
+	 * @return The literal byte contents of the given section of the file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong reading the file.
+	 */
+	@Nonnull
+	byte[] getContents(int offset, int length) throws RemoteException,
+			IOException;
+
+	/**
+	 * Write the data to the file, totally replacing what was there before.
+	 * 
+	 * @param data
+	 *            The literal bytes that will form the new contents of the file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong writing the contents.
+	 */
+	void setContents(@Nonnull byte[] data) throws RemoteException, IOException;
+
+	/**
+	 * Append the data to the file.
+	 * 
+	 * @param data
+	 *            The literal bytes that will be appended.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong writing the contents.
+	 */
+	void appendContents(@Nonnull byte[] data) throws RemoteException,
+			IOException;
+
+	/**
+	 * @return The length of the file, in bytes.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	long getSize() throws RemoteException;
+
+	/**
+	 * Copy from another file to this one.
+	 * 
+	 * @param sourceFile
+	 *            The other file to copy from.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong during the copy.
+	 */
+	void copy(@Nonnull RemoteFile sourceFile) throws RemoteException,
+			IOException;
+
+	/**
+	 * @return The full native OS name for the file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	String getNativeName() throws RemoteException;
+
+	/**
+	 * @return The host holding the file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	String getNativeHost() throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
new file mode 100644
index 0000000..7a7510c
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * This represents the assignment of inputs to input ports of the workflow. Note
+ * that the <tt>file</tt> and <tt>value</tt> properties are never set at the
+ * same time.
+ * 
+ * @author Donal Fellows
+ */
+public interface RemoteInput extends Remote {
+	/**
+	 * @return The file currently assigned to this input port, or <tt>null</tt>
+	 *         if no file is assigned.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	String getFile() throws RemoteException;
+
+	/**
+	 * @return The name of this input port. This may not be changed.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	String getName() throws RemoteException;
+
+	/**
+	 * @return The value currently assigned to this input port, or <tt>null</tt>
+	 *         if no value is assigned.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	String getValue() throws RemoteException;
+
+	/**
+	 * @return The delimiter currently used to split this input port's value
+	 *         into a list, or <tt>null</tt> if no delimiter is to be used
+	 *         (i.e., the value is a singleton).
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	String getDelimiter() throws RemoteException;
+
+	/**
+	 * Sets the file to use for this input. This overrides the use of the
+	 * previous file and any set value.
+	 * 
+	 * @param file
+	 *            The filename to use. Must not start with a <tt>/</tt> or
+	 *            contain any <tt>..</tt> segments. Will be interpreted relative
+	 *            to the run's working directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setFile(@Nonnull String file) throws RemoteException;
+
+	/**
+	 * Sets the value to use for this input. This overrides the use of the
+	 * previous value and any set file.
+	 * 
+	 * @param value
+	 *            The value to use.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setValue(@Nonnull String value) throws RemoteException;
+
+	/**
+	 * Sets the delimiter used to split this input port's value into a list.
+	 * 
+	 * @param delimiter
+	 *            The delimiter character, or <tt>null</tt> if no delimiter is
+	 *            to be used (i.e., the value is a singleton).
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setDelimiter(@Nullable String delimiter) throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
new file mode 100644
index 0000000..4001721
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * An event listener that is attached to a {@link RemoteSingleRun}.
+ * 
+ * @author Donal Fellows
+ */
+public interface RemoteListener extends Remote {
+	/**
+	 * @return The name of the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getName() throws RemoteException;
+
+	/**
+	 * @return The type of the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getType() throws RemoteException;
+
+	/**
+	 * @return The configuration document for the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getConfiguration() throws RemoteException;
+
+	/**
+	 * @return The supported properties of the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String[] listProperties() throws RemoteException;
+
+	/**
+	 * Get the value of a particular property, which should be listed in the
+	 * {@link #listProperties()} method.
+	 * 
+	 * @param propName
+	 *            The name of the property to read.
+	 * @return The value of the property.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getProperty(@Nonnull String propName) throws RemoteException;
+
+	/**
+	 * Set the value of a particular property, which should be listed in the
+	 * {@link #listProperties()} method.
+	 * 
+	 * @param propName
+	 *            The name of the property to write.
+	 * @param value
+	 *            The value to set the property to.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	public void setProperty(@Nonnull String propName, @Nonnull String value)
+			throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
new file mode 100644
index 0000000..eec4ab5
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.UUID;
+
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * The main RMI-enabled interface for creating runs.
+ * 
+ * @author Donal Fellows
+ */
+public interface RemoteRunFactory extends Remote {
+	/**
+	 * Makes a workflow run that will process a particular workflow document.
+	 * 
+	 * @param workflow
+	 *            The (serialised) workflow to instantiate as a run.
+	 * @param creator
+	 *            Who is this run created for?
+	 * @param usageRecordReceiver
+	 *            Where to write any usage records. May be <tt>null</tt> to
+	 *            cause them to not be written.
+	 * @param masterID
+	 *            The UUID of the run to use, or <tt>null</tt> if the execution
+	 *            engine is to manufacture a new one for itself.
+	 * @return A remote handle for the run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	RemoteSingleRun make(@Nonnull byte[] workflow, @Nonnull String creator,
+			@Nullable UsageRecordReceiver usageRecordReceiver,
+			@Nullable UUID masterID) throws RemoteException;
+
+	/**
+	 * Asks this factory to unregister itself from the registry and cease
+	 * operation.
+	 * 
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void shutdown() throws RemoteException;
+
+	/**
+	 * Configures the details to use when setting up the workflow run's
+	 * connnection to the interaction feed.
+	 * 
+	 * @param host
+	 *            The host where the feed is located.
+	 * @param port
+	 *            The port where the feed is located.
+	 * @param webdavPath
+	 *            The path used for pushing web pages into the feed.
+	 * @param feedPath
+	 *            The path used for reading and writing notifications on the
+	 *            feed.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setInteractionServiceDetails(@Nonnull String host,
+			@Nonnull String port, @Nonnull String webdavPath,
+			@Nonnull String feedPath) throws RemoteException;
+
+	/**
+	 * Gets a count of the number of {@linkplain RemoteSingleRun workflow runs}
+	 * that this factor knows about that are in the
+	 * {@link RemoteStatus#Operating Operating} state.
+	 * 
+	 * @return A count of "running" workflow runs.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	int countOperatingRuns() throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
new file mode 100644
index 0000000..35e6c09
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.net.URI;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Outline of the security context for a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+public interface RemoteSecurityContext extends Remote {
+	void setKeystore(@Nonnull byte[] keystore) throws RemoteException,
+			ImplementationException;
+
+	void setPassword(@Nonnull char[] password) throws RemoteException,
+			ImplementationException;
+
+	void setTruststore(@Nonnull byte[] truststore) throws RemoteException,
+			ImplementationException;
+
+	void setUriToAliasMap(@Nonnull Map<URI, String> uriToAliasMap)
+			throws RemoteException;
+
+	void setHelioToken(@Nonnull String helioToken) throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
new file mode 100644
index 0000000..fa68b81
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.net.URL;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public interface RemoteSingleRun extends Remote {
+	/**
+	 * @return The name of the Baclava file to use for all inputs, or
+	 *         <tt>null</tt> if no Baclava file is set.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public String getInputBaclavaFile() throws RemoteException;
+
+	/**
+	 * Sets the Baclava file to use for all inputs. This overrides the use of
+	 * individual inputs.
+	 * 
+	 * @param filename
+	 *            The filename to use. Must not start with a <tt>/</tt> or
+	 *            contain any <tt>..</tt> segments. Will be interpreted relative
+	 *            to the run's working directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	public void setInputBaclavaFile(@Nonnull String filename)
+			throws RemoteException;
+
+	/**
+	 * @return The list of input assignments.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public List<RemoteInput> getInputs() throws RemoteException;
+
+	/**
+	 * Create an input assignment.
+	 * 
+	 * @param name
+	 *            The name of the port that this will be an input for.
+	 * @return The assignment reference.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public RemoteInput makeInput(@Nonnull String name) throws RemoteException;
+
+	/**
+	 * @return The file (relative to the working directory) to write the outputs
+	 *         of the run to as a Baclava document, or <tt>null</tt> if they are
+	 *         to be written to non-Baclava files in a directory called
+	 *         <tt>out</tt>.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public String getOutputBaclavaFile() throws RemoteException;
+
+	/**
+	 * Sets where the output of the run is to be written to. This will cause the
+	 * output to be generated as a Baclava document, rather than a collection of
+	 * individual non-Baclava files in the subdirectory of the working directory
+	 * called <tt>out</tt>.
+	 * 
+	 * @param filename
+	 *            Where to write the Baclava file (or <tt>null</tt> to cause the
+	 *            output to be written to individual files); overwrites any
+	 *            previous setting of this value.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	public void setOutputBaclavaFile(@Nullable String filename)
+			throws RemoteException;
+
+	/**
+	 * @return The current status of the run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public RemoteStatus getStatus() throws RemoteException;
+
+	/**
+	 * Set the status of the run, which should cause it to move into the given
+	 * state. This may cause some significant changes.
+	 * 
+	 * @param s
+	 *            The state to try to change to.
+	 * @throws IllegalStateTransitionException
+	 *             If the requested state change is impossible. (Note that it is
+	 *             always legal to set the status to the current status.)
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws ImplementationException
+	 *             If something goes horribly wrong on the back end.
+	 * @throws StillWorkingOnItException
+	 *             If the startup time of the workflow implementation exceeds a
+	 *             built-in threshold.
+	 */
+	public void setStatus(@Nonnull RemoteStatus s)
+			throws IllegalStateTransitionException, RemoteException,
+			ImplementationException, StillWorkingOnItException;
+
+	/**
+	 * @return When this workflow run was found to have finished, or
+	 *         <tt>null</tt> if it has never finished (either still running or
+	 *         never started).
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public Date getFinishTimestamp() throws RemoteException;
+
+	/**
+	 * @return When this workflow run was started, or <tt>null</tt> if it has
+	 *         never been started.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public Date getStartTimestamp() throws RemoteException;
+
+	/**
+	 * @return Handle to the main working directory of the run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public RemoteDirectory getWorkingDirectory() throws RemoteException;
+
+	/**
+	 * @return The list of listener instances attached to the run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public List<RemoteListener> getListeners() throws RemoteException;
+
+	/**
+	 * Add a listener to the run.
+	 * 
+	 * @param listener
+	 *            The listener to add.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws ImplementationException
+	 *             If something goes wrong when adding the listener.
+	 */
+	public void addListener(@Nonnull RemoteListener listener)
+			throws RemoteException, ImplementationException;
+
+	/**
+	 * @return The security context structure for this run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws ImplementationException
+	 *             If something goes wrong when getting the context.
+	 */
+	@Nonnull
+	public RemoteSecurityContext getSecurityContext() throws RemoteException,
+			ImplementationException;
+
+	/**
+	 * Kill off this run, removing all resources which it consumes.
+	 * 
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws ImplementationException
+	 *             If something goes horribly wrong when destroying the run.
+	 */
+	public void destroy() throws RemoteException, ImplementationException;
+
+	/**
+	 * Get the types of listener supported by this run.
+	 * 
+	 * @return A list of listener type names.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public List<String> getListenerTypes() throws RemoteException;
+
+	/**
+	 * Create a listener that can be attached to this run.
+	 * 
+	 * @param type
+	 *            The type name of the listener to create; it must be one of the
+	 *            names returned by the {@link #getListenerTypes()} operation.
+	 * @param configuration
+	 *            The configuration document for this listener. The nature of
+	 *            the contents of this are determined by the type.
+	 * @return A handle for the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public RemoteListener makeListener(@Nonnull String type,
+			@Nonnull String configuration) throws RemoteException;
+
+	/**
+	 * Configures the details to use when setting up the workflow run's
+	 * connnection to the interaction feed.
+	 * 
+	 * @param interactionFeed
+	 *            The location of the interaction feed. If <tt>null</tt>,
+	 *            defaults from the factory will be used instead.
+	 * @param webdavPath
+	 *            The location used for pushing web pages to support the feed.
+	 *            If <tt>null</tt>, a default from the factory will be used
+	 *            instead.
+	 * @param publishUrlBase
+	 *            Where to <i>actually</i> publish to, if this needs to be
+	 *            different from the location presented in the published HTML
+	 *            and Feed entries. Necessary in complex network scenarios.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setInteractionServiceDetails(@Nonnull URL interactionFeed,
+			@Nonnull URL webdavPath, @Nullable URL publishUrlBase) throws RemoteException;
+
+	/**
+	 * A do-nothing method, used to check the general reachability of the
+	 * workflow run.
+	 * 
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void ping() throws RemoteException;
+
+	/**
+	 * Sets whether we should generate provenance information from a run.
+	 * 
+	 * @param generateProvenance
+	 *            Boolean flag, true for do the generation. Must be set before
+	 *            starting the run for this to have an effect.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setGenerateProvenance(boolean generateProvenance)
+			throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
new file mode 100644
index 0000000..db039f0
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+/**
+ * States of a workflow run. They are {@link RemoteStatus#Initialized
+ * Initialized}, {@link RemoteStatus#Operating Operating},
+ * {@link RemoteStatus#Stopped Stopped}, and {@link RemoteStatus#Finished
+ * Finished}. Conceptually, there is also a <tt>Destroyed</tt> state, but the
+ * workflow run does not exist (and hence can't have its state queried or set)
+ * in that case.
+ * 
+ * @author Donal Fellows
+ */
+public enum RemoteStatus {
+	/**
+	 * The workflow run has been created, but is not yet running. The run will
+	 * need to be manually moved to {@link #Operating} when ready.
+	 */
+	Initialized,
+	/**
+	 * The workflow run is going, reading input, generating output, etc. Will
+	 * eventually either move automatically to {@link #Finished} or can be moved
+	 * manually to {@link #Stopped} (where supported).
+	 */
+	Operating,
+	/**
+	 * The workflow run is paused, and will need to be moved back to
+	 * {@link #Operating} manually.
+	 */
+	Stopped,
+	/**
+	 * The workflow run has ceased; data files will continue to exist until the
+	 * run is destroyed (which may be manual or automatic).
+	 */
+	Finished
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
new file mode 100644
index 0000000..4643d5c
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+/**
+ * Exception that indicates that the implementation is still working on
+ * processing the operation. Note that though this is an exception, it is <i>not
+ * a failure</i>.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+public class StillWorkingOnItException extends Exception {
+	public StillWorkingOnItException(String string) {
+		super(string);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
new file mode 100644
index 0000000..9880a3b
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Interfaces exported by worker classes to the server.
+ */
+package org.taverna.server.localworker.remote;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
new file mode 100644
index 0000000..89c29ae
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.server;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Interface exported by (part of) the webapp to allow processes it creates to
+ * push in usage records.
+ * 
+ * @author Donal Fellows
+ */
+public interface UsageRecordReceiver extends Remote {
+	/**
+	 * Called to push in a usage record. Note that it is assumed that the usage
+	 * record already contains all the information required to locate and
+	 * process the job; there is no separate handle.
+	 * 
+	 * @param usageRecord
+	 *            The serialised XML of the usage record.
+	 * @throws RemoteException
+	 *             if anything goes wrong.
+	 */
+	void acceptUsageRecord(String usageRecord) throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
new file mode 100644
index 0000000..cdd592b
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Interfaces exported by the server to worker classes.
+ */
+package org.taverna.server.localworker.server;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-unix-forker/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-unix-forker/pom.xml b/taverna-server-unix-forker/pom.xml
new file mode 100644
index 0000000..a2beeb4
--- /dev/null
+++ b/taverna-server-unix-forker/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project 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.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-unix-forker</artifactId>
+	<name>Apache Taverna Server Impersonation Module (Unix)</name>
+	<description>Manages the starting of the worker processes as different users. Unix-specific.</description>
+
+	<properties>
+		<project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
+		<forkerMainClass>org.taverna.server.unixforker.Forker</forkerMainClass>
+	</properties>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<descriptorRefs>
+						<descriptorRef>jar-with-dependencies</descriptorRef>
+					</descriptorRefs>
+					<archive>
+						<manifest>
+							<mainClass>${forkerMainClass}</mainClass>
+						</manifest>
+					</archive>
+				</configuration>
+				<executions>
+					<execution>
+						<id>make-assembly</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
----------------------------------------------------------------------
diff --git a/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java b/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
new file mode 100644
index 0000000..f9dc632
--- /dev/null
+++ b/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.unixforker;
+
+import static java.lang.System.err;
+import static java.lang.System.getProperty;
+import static java.lang.System.in;
+import static java.lang.System.out;
+import static java.util.Arrays.asList;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A simple class that forks off processes when asked to over its standard
+ * input. The one complication is that it forks them off as other users, through
+ * the use of the <tt>sudo</tt> utility. It is Unix-specific.
+ * 
+ * @author Donal Fellows
+ */
+public class Forker extends Thread {
+	private static String password;
+	private static BufferedReader br;
+
+	/**
+	 * Helper to make reading a password from a file clearer. The password must
+	 * be the first line of the file.
+	 * 
+	 * @param passwordFile
+	 *            The file to load from.
+	 * @throws IOException
+	 *             If anything goes wrong.
+	 */
+	private static void loadPassword(@Nonnull File passwordFile)
+			throws IOException {
+		try {
+			err.println("attempting to load password from " + passwordFile);
+			try (FileReader fr = new FileReader(passwordFile)) {
+				password = new BufferedReader(fr).readLine();
+			}
+		} catch (IOException e) {
+			err.println("failed to read password from file " + passwordFile
+					+ "described in password.file property");
+			throw e;
+		}
+	}
+
+	/**
+	 * Initialization code, which runs before the main loop starts processing.
+	 * 
+	 * @param args
+	 *            The arguments to the program.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	public static void init(String[] args) throws Exception {
+		if (args.length < 1)
+			throw new IllegalArgumentException(
+					"wrong # args: must be \"program ?argument ...?\"");
+		if (getProperty("password.file") != null)
+			loadPassword(new File(getProperty("password.file")));
+		if (password == null)
+			err.println("no password.file property or empty file; "
+					+ "assuming password-less sudo is configured");
+		else
+			err.println("password is of length " + password.length());
+		br = new BufferedReader(new InputStreamReader(in));
+	}
+
+	/**
+	 * The body of the main loop of this program.
+	 * 
+	 * @param args
+	 *            The arguments to use when running the other program.
+	 * @return Whether to repeat the loop.
+	 * @throws Exception
+	 *             If anything goes wrong. Note that the loop is repeated if an
+	 *             exception occurs in it.
+	 */
+	public static boolean mainLoopBody(String[] args) throws Exception {
+		String line = br.readLine();
+		if (line == null)
+			return false;
+		List<String> vals = asList(line.split("[ \t]+"));
+		if (vals.size() != 2) {
+			out.println("wrong # values: must be \"username UUID\"");
+			return true;
+		}
+		ProcessBuilder pb = new ProcessBuilder();
+		pb.command()
+				.addAll(asList("sudo", "-u", vals.get(0), "-S", "-H", "--"));
+		pb.command().addAll(asList(args));
+		pb.command().add(vals.get(1));
+		Forker f = new Forker(pb);
+		f.setDaemon(true);
+		f.start();
+		return true;
+	}
+
+	/**
+	 * The main code for this class, which turns this into an executable
+	 * program. Runs the initialisation and then the main loop, in both cases
+	 * with appropriate error handling.
+	 * 
+	 * @param args
+	 *            Arguments to this program.
+	 */
+	public static void main(String... args) {
+		try {
+			init(args);
+			while (true) {
+				try {
+					if (!mainLoopBody(args))
+						break;
+				} catch (Exception e) {
+					e.printStackTrace(err);
+					out.println(e.getClass().getName() + ": " + e.getMessage());
+				}
+			}
+			System.exit(0);
+		} catch (Exception e) {
+			e.printStackTrace(err);
+			System.exit(1);
+		}
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	public Forker(ProcessBuilder pb) throws IOException {
+		out.println("Starting subprocess: " + pb.command());
+		final Process p = pb.start();
+		abstract class ProcessAttachedDaemon extends Thread {
+			public ProcessAttachedDaemon() {
+				setDaemon(true);
+				start();
+			}
+
+			abstract void act() throws Exception;
+
+			@Override
+			public final void run() {
+				try {
+					act();
+					p.waitFor();
+				} catch (InterruptedException e) {
+					// Just drop
+				} catch (Exception e) {
+					p.destroy();
+					e.printStackTrace(err);
+				}
+			}
+		}
+		new ProcessAttachedDaemon() {
+			@Override
+			void act() throws Exception {
+				copyFromSudo("Subprocess(out):", p.getInputStream());
+			}
+		};
+		new ProcessAttachedDaemon() {
+			@Override
+			void act() throws Exception {
+				copyFromSudo("Subprocess(err):", p.getErrorStream());
+			}
+		};
+		new ProcessAttachedDaemon() {
+			@Override
+			void act() throws Exception {
+				interactWithSudo(p.getOutputStream());
+			}
+		};
+	}
+
+	protected void interactWithSudo(OutputStream os) throws Exception {
+		if (password != null) {
+			OutputStreamWriter osw = new OutputStreamWriter(os);
+			osw.write(password + "\n");
+			osw.flush();
+		}
+		os.close();
+	}
+
+	protected void copyFromSudo(String header, InputStream sudoStream)
+			throws Exception {
+		int b = '\n';
+		while (true) {
+			if (b == '\n')
+				out.print(header);
+			b = sudoStream.read();
+			if (b == -1)
+				break;
+			out.write(b);
+			out.flush();
+		}
+		sudoStream.close();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/.gitignore
----------------------------------------------------------------------
diff --git a/taverna-server-usagerecord/.gitignore b/taverna-server-usagerecord/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/taverna-server-usagerecord/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-usagerecord/pom.xml b/taverna-server-usagerecord/pom.xml
new file mode 100644
index 0000000..47ab732
--- /dev/null
+++ b/taverna-server-usagerecord/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project 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.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-usagerecord</artifactId>
+	<name>Apache Taverna Server Usage Record Support</name>
+	<description>Basic Java bindings for the OGF Usage Record Format, version 1.0, plus a simple wrapper to make working with it easier.</description>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>jaxb2-maven-plugin</artifactId>
+				<version>1.3.1</version>
+				<executions>
+					<execution>
+						<id>xsd2java</id>
+						<goals>
+							<goal>xjc</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${project.build.directory}/generated-sources/xjc</outputDirectory>
+							<schemaDirectory>${basedir}/src/main/xsd</schemaDirectory>
+						</configuration>
+					</execution>
+				</executions>
+			</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.codehaus.mojo</groupId>
+										<artifactId>jaxb2-maven-plugin</artifactId>
+										<versionRange>[1.3.1,)</versionRange>
+										<goals>
+											<goal>xjc</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<execute />
+									</action>
+								</pluginExecution>
+							</pluginExecutions>
+						</lifecycleMappingMetadata>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+</project>