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 2018/01/09 23:30:17 UTC

[01/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Repository: incubator-taverna-server
Updated Branches:
  refs/heads/master 63fdb899d -> 46777e2c6


http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/test/java/org/apache/taverna/server/localworker/impl/LocalWorkerTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/test/java/org/apache/taverna/server/localworker/impl/LocalWorkerTest.java b/taverna-server-worker/src/test/java/org/apache/taverna/server/localworker/impl/LocalWorkerTest.java
new file mode 100644
index 0000000..084738f
--- /dev/null
+++ b/taverna-server-worker/src/test/java/org/apache/taverna/server/localworker/impl/LocalWorkerTest.java
@@ -0,0 +1,564 @@
+/*
+ */
+package org.taverna.server.localworker.impl;
+/*
+ * 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.
+ */
+
+import static java.util.UUID.randomUUID;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.taverna.server.localworker.impl.LocalWorker.DO_MKDIR;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.taverna.server.localworker.api.Worker;
+import org.taverna.server.localworker.api.WorkerFactory;
+import org.taverna.server.localworker.remote.IllegalStateTransitionException;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteInput;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+public class LocalWorkerTest {
+	LocalWorker lw;
+	static List<String> events;
+
+	public static RemoteStatus returnThisStatus = RemoteStatus.Operating;
+
+	static class DummyWorker implements Worker {
+		@Override
+		public RemoteListener getDefaultListener() {
+			return new RemoteListener() {
+				@Override
+				public String getConfiguration() {
+					return "RLCONFIG";
+				}
+
+				@Override
+				public String getName() {
+					return "RLNAME";
+				}
+
+				@Override
+				public String getProperty(String propName) {
+					return "RLPROP[" + propName + "]";
+				}
+
+				@Override
+				public String getType() {
+					return "RLTYPE";
+				}
+
+				@Override
+				public String[] listProperties() {
+					return new String[] { "RLP1", "RLP2" };
+				}
+
+				@Override
+				public void setProperty(String propName, String value) {
+					events.add("setProperty[");
+					events.add(propName);
+					events.add(value);
+					events.add("]");
+				}
+			};
+		}
+
+		@Override
+		public RemoteStatus getWorkerStatus() {
+			events.add("status=" + returnThisStatus);
+			return returnThisStatus;
+		}
+
+		@Override
+		public boolean initWorker(LocalWorker local,
+				String executeWorkflowCommand, byte[] workflow,
+				File workingDir, File inputBaclava,
+				Map<String, File> inputFiles, Map<String, String> inputValues,
+				Map<String, String> delimiters, File outputBaclava, File cmdir,
+				char[] cmpass, boolean doprov, Map<String, String> env,
+				String id, List<String> conf) throws Exception {
+			events.add("init[");
+			events.add(executeWorkflowCommand);
+			events.add(new String(workflow, "UTF-8"));
+			int dirLen = workingDir.getName().length();
+			events.add(Integer.toString(dirLen));
+			events.add(inputBaclava == null ? "<null>" : inputBaclava
+					.toString().substring(dirLen));
+			Map<String, String> in = new TreeMap<>();
+			for (Entry<String, File> name : inputFiles.entrySet())
+				in.put(name.getKey(), name.getValue() == null ? "<null>" : name
+						.getValue().getName());
+			events.add(in.toString());
+			events.add(new TreeMap<>(inputValues).toString());
+			events.add(outputBaclava == null ? "<null>" : outputBaclava
+					.getName());
+			// TODO: check cmdir and cmpass
+			// TODO: check doprov
+			// TODO: log env
+			// TODO: check delimiters
+			events.add("]");
+			return true;
+		}
+
+		@Override
+		public void killWorker() throws Exception {
+			events.add("kill");
+		}
+
+		@Override
+		public void startWorker() throws Exception {
+			events.add("start");
+		}
+
+		@Override
+		public void stopWorker() throws Exception {
+			events.add("stop");
+		}
+
+		@Override
+		public void setURReceiver(UsageRecordReceiver receiver) {
+			// We just ignore this
+		}
+
+		@Override
+		public void deleteLocalResources() throws ImplementationException {
+			// Nothing to do here
+		}
+	}
+
+	WorkerFactory factory = new WorkerFactory() {
+		@Override
+		public Worker makeInstance() throws Exception {
+			return new DummyWorker();
+		}
+	};
+
+	@Before
+	public void setUp() throws Exception {
+		lw = new LocalWorker("XWC", "WF".getBytes("UTF-8"), null, randomUUID(),
+				new HashMap<String, String>(), new ArrayList<String>(), factory);
+		events = new ArrayList<>();
+		returnThisStatus = RemoteStatus.Operating;
+	}
+
+	@After
+	public void tearDown() throws Exception {
+		lw.destroy();
+	}
+
+	private List<String> l(String... strings) {
+		return Arrays.asList(strings);
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	@Test
+	public void testDestroy1() throws Exception {
+		lw.destroy();
+		assertEquals(l(), events);
+	}
+
+	@Test
+	public void testDestroy2() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.destroy();
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "kill"), events);
+	}
+
+	@Test
+	public void testDestroy3() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.destroy();
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "stop", "kill"), events);
+	}
+
+	@Test
+	public void testDestroy4() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Finished);
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "kill"), events);
+		lw.destroy();
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "kill"), events);
+	}
+
+	@Test
+	public void testAddListener() {
+		Throwable t = null;
+		try {
+			lw.addListener(null);
+		} catch (Throwable caught) {
+			t = caught;
+		}
+		assertNotNull(t);
+		assertSame(ImplementationException.class, t.getClass());
+		assertNotNull(t.getMessage());
+		assertEquals("not implemented", t.getMessage());
+	}
+
+	@Test
+	public void testGetInputBaclavaFile() throws Exception {
+		assertNull(lw.getInputBaclavaFile());
+		lw.setInputBaclavaFile("IBaclava");
+		assertNotNull(lw.getInputBaclavaFile());
+		assertEquals("IBaclava", lw.getInputBaclavaFile());
+		lw.makeInput("FOO").setValue("BAR");
+		assertNull(lw.getInputBaclavaFile());
+	}
+
+	@Test
+	public void testGetInputsWithValue() throws Exception {
+		assertEquals(0, lw.getInputs().size());
+
+		lw.makeInput("FOO").setValue("BAR");
+
+		assertEquals(1, lw.getInputs().size());
+		assertEquals("FOO", lw.getInputs().get(0).getName());
+		assertNull(lw.getInputs().get(0).getFile());
+		assertNotNull(lw.getInputs().get(0).getValue());
+
+		lw.setInputBaclavaFile("BLAH");
+
+		assertEquals(1, lw.getInputs().size());
+		assertNull(lw.getInputs().get(0).getFile());
+		assertNull(lw.getInputs().get(0).getValue());
+	}
+
+	@Test
+	public void testGetInputsWithFile() throws Exception {
+		assertEquals(0, lw.getInputs().size());
+
+		lw.makeInput("BAR").setFile("FOO");
+
+		assertEquals(1, lw.getInputs().size());
+		assertEquals("BAR", lw.getInputs().get(0).getName());
+		assertNotNull(lw.getInputs().get(0).getFile());
+		assertNull(lw.getInputs().get(0).getValue());
+
+		lw.setInputBaclavaFile("BLAH");
+
+		assertEquals(1, lw.getInputs().size());
+		assertNull(lw.getInputs().get(0).getFile());
+		assertNull(lw.getInputs().get(0).getValue());
+	}
+
+	@Test
+	public void testGetListenerTypes() {
+		assertEquals("[]", lw.getListenerTypes().toString());
+	}
+
+	@Test
+	public void testGetListeners() throws Exception {
+		assertEquals(1, lw.getListeners().size());
+		RemoteListener rl = lw.getListeners().get(0);
+		assertEquals("RLNAME", rl.getName());
+		assertEquals("RLCONFIG", rl.getConfiguration());
+		assertEquals("RLTYPE", rl.getType());
+		assertEquals("[RLP1, RLP2]", Arrays.asList(rl.listProperties())
+				.toString());
+		assertEquals("RLPROP[RLP1]", rl.getProperty("RLP1"));
+		assertEquals("RLPROP[RLP2]", rl.getProperty("RLP2"));
+		rl.setProperty("FOOBAR", "BARFOO");
+		assertEquals(l("setProperty[", "FOOBAR", "BARFOO", "]"), events);
+	}
+
+	@Test
+	public void testGetOutputBaclavaFile() throws Exception {
+		assertNull(lw.getOutputBaclavaFile());
+		lw.setOutputBaclavaFile("notnull");
+		assertEquals("notnull", lw.getOutputBaclavaFile());
+		lw.setOutputBaclavaFile(null);
+		assertNull(lw.getOutputBaclavaFile());
+	}
+
+	@Test
+	public void testGetSecurityContext() throws Exception {
+		boolean md = DO_MKDIR;
+		LocalWorker.DO_MKDIR = false; // HACK! Work around Hudson problem...
+		try {
+			assertNotNull(lw.getSecurityContext());
+		} finally {
+			LocalWorker.DO_MKDIR = md;
+		}
+	}
+
+	@Test
+	public void testGetStatusInitial() {
+		assertEquals(RemoteStatus.Initialized, lw.getStatus());
+	}
+
+	@Test
+	public void testGetStatus() throws Exception {
+		assertEquals(RemoteStatus.Initialized, lw.getStatus());
+		returnThisStatus = RemoteStatus.Operating;
+		assertEquals(RemoteStatus.Initialized, lw.getStatus());
+		lw.setStatus(RemoteStatus.Operating);
+		assertEquals(RemoteStatus.Operating, lw.getStatus());
+		assertEquals(RemoteStatus.Operating, lw.getStatus());
+		returnThisStatus = RemoteStatus.Finished;
+		assertEquals(RemoteStatus.Finished, lw.getStatus());
+		returnThisStatus = RemoteStatus.Stopped;
+		assertEquals(RemoteStatus.Finished, lw.getStatus());
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "status=Operating", "status=Operating",
+						"status=Finished"), events);
+	}
+
+	@Test
+	public void testGetWorkingDirectory() throws Exception {
+		RemoteDirectory rd = lw.getWorkingDirectory();
+		assertNotNull(rd);
+		assertNotNull(rd.getContents());
+		assertNull(rd.getContainingDirectory());
+		assertNotNull(rd.getName());
+		assertEquals(-1, rd.getName().indexOf('/'));
+		assertFalse("..".equals(rd.getName()));
+		assertEquals("", rd.getName());
+	}
+
+	@Test
+	public void testValidateFilename() throws Exception {
+		lw.validateFilename("foobar");
+		lw.validateFilename("foo/bar");
+		lw.validateFilename("foo.bar");
+		lw.validateFilename("foo..bar");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad0() throws Exception {
+		lw.validateFilename("./.");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad1() throws Exception {
+		lw.validateFilename("/");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad2() throws Exception {
+		lw.validateFilename("");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad3() throws Exception {
+		lw.validateFilename(null);
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad4() throws Exception {
+		lw.validateFilename("..");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad5() throws Exception {
+		lw.validateFilename("foo/../bar");
+	}
+
+	@Test
+	public void testMakeInput() throws Exception {
+		assertEquals(0, lw.getInputs().size());
+
+		RemoteInput ri = lw.makeInput("TEST");
+
+		assertNotNull(ri);
+		assertEquals(1, lw.getInputs().size());
+		assertNotSame(ri, lw.getInputs().get(0)); // different delegates
+		assertEquals("TEST", ri.getName());
+		assertNull(ri.getFile());
+		assertNull(ri.getValue());
+
+		lw.setInputBaclavaFile("bad");
+		ri.setFile("good");
+		assertEquals("good", ri.getFile());
+		assertNull(lw.getInputBaclavaFile());
+		ri.setValue("very good");
+		assertEquals("very good", ri.getValue());
+		assertNull(ri.getFile());
+		assertNull(lw.getInputBaclavaFile());
+
+		lw.makeInput("TEST2");
+		assertEquals(2, lw.getInputs().size());
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testMakeInputFileSanity() throws Exception {
+		lw.makeInput("foo").setFile("/../bar");
+	}
+
+	@Test
+	public void testMakeListener() {
+		Throwable t = null;
+		try {
+			lw.makeListener("?", "?");
+		} catch (Throwable caught) {
+			t = caught;
+		}
+		assertNotNull(t);
+		assertSame(RemoteException.class, t.getClass());
+		assertNotNull(t.getMessage());
+		assertEquals("listener manufacturing unsupported", t.getMessage());
+	}
+
+	@Test
+	public void testSetInputBaclavaFile1() throws Exception {
+		assertNull(lw.getInputBaclavaFile());
+		lw.setInputBaclavaFile("eg");
+		assertEquals("eg", lw.getInputBaclavaFile());
+	}
+
+	@Test
+	public void testSetInputBaclavaFile2() throws Exception {
+		RemoteInput ri = lw.makeInput("foo");
+		ri.setValue("bar");
+		assertEquals("bar", ri.getValue());
+		lw.setInputBaclavaFile("eg");
+		assertNull(ri.getValue());
+	}
+
+	@Test
+	public void testSetOutputBaclavaFile1() throws Exception {
+		assertNull(lw.outputBaclava);
+		lw.setOutputBaclavaFile("foobar");
+		assertEquals("foobar", lw.outputBaclava);
+		assertEquals("foobar", lw.getOutputBaclavaFile());
+		lw.setOutputBaclavaFile("foo/bar");
+		assertEquals("foo/bar", lw.outputBaclava);
+		assertEquals("foo/bar", lw.getOutputBaclavaFile());
+		lw.setOutputBaclavaFile(null);
+		assertNull(lw.outputBaclava);
+		assertNull(lw.getOutputBaclavaFile());
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testSetOutputBaclavaFile2() throws Exception {
+		lw.setOutputBaclavaFile("/foobar");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testSetOutputBaclavaFile3() throws Exception {
+		lw.setOutputBaclavaFile("foo/../bar");
+	}
+
+	@Test
+	public void testSetStatus0() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Finished);
+		lw.setStatus(RemoteStatus.Finished);
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "stop", "start", "kill"), events);
+	}
+
+	@Test
+	public void testSetStatus1() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.setStatus(RemoteStatus.Finished);
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "stop", "kill"), events);
+	}
+
+	@Test
+	public void testSetStatus2() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Finished);
+		assertEquals(l(), events);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus3() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Finished);
+		lw.setStatus(RemoteStatus.Initialized);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus4() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Initialized);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus5() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Stopped);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus6() throws Exception {
+		lw.setStatus(RemoteStatus.Finished);
+		lw.setStatus(RemoteStatus.Stopped);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus7() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.setStatus(RemoteStatus.Initialized);
+	}
+
+	@Test
+	public void testLifecycle() throws Exception {
+		lw.makeInput("foo").setFile("foofile");
+		lw.makeInput("bar").setValue("barvalue");
+		lw.setOutputBaclavaFile("spong");
+		lw.setOutputBaclavaFile("boo");
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Finished);
+		// Assumes order of map, so fragile but works...
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>",
+						"{bar=<null>, foo=foofile}",
+						"{bar=barvalue, foo=null}", "boo", "]", "kill"), events);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java b/taverna-server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java
deleted file mode 100644
index 084738f..0000000
--- a/taverna-server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.impl;
-/*
- * 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.
- */
-
-import static java.util.UUID.randomUUID;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.taverna.server.localworker.impl.LocalWorker.DO_MKDIR;
-
-import java.io.File;
-import java.rmi.RemoteException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.api.WorkerFactory;
-import org.taverna.server.localworker.remote.IllegalStateTransitionException;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteInput;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-
-public class LocalWorkerTest {
-	LocalWorker lw;
-	static List<String> events;
-
-	public static RemoteStatus returnThisStatus = RemoteStatus.Operating;
-
-	static class DummyWorker implements Worker {
-		@Override
-		public RemoteListener getDefaultListener() {
-			return new RemoteListener() {
-				@Override
-				public String getConfiguration() {
-					return "RLCONFIG";
-				}
-
-				@Override
-				public String getName() {
-					return "RLNAME";
-				}
-
-				@Override
-				public String getProperty(String propName) {
-					return "RLPROP[" + propName + "]";
-				}
-
-				@Override
-				public String getType() {
-					return "RLTYPE";
-				}
-
-				@Override
-				public String[] listProperties() {
-					return new String[] { "RLP1", "RLP2" };
-				}
-
-				@Override
-				public void setProperty(String propName, String value) {
-					events.add("setProperty[");
-					events.add(propName);
-					events.add(value);
-					events.add("]");
-				}
-			};
-		}
-
-		@Override
-		public RemoteStatus getWorkerStatus() {
-			events.add("status=" + returnThisStatus);
-			return returnThisStatus;
-		}
-
-		@Override
-		public boolean initWorker(LocalWorker local,
-				String executeWorkflowCommand, byte[] workflow,
-				File workingDir, File inputBaclava,
-				Map<String, File> inputFiles, Map<String, String> inputValues,
-				Map<String, String> delimiters, File outputBaclava, File cmdir,
-				char[] cmpass, boolean doprov, Map<String, String> env,
-				String id, List<String> conf) throws Exception {
-			events.add("init[");
-			events.add(executeWorkflowCommand);
-			events.add(new String(workflow, "UTF-8"));
-			int dirLen = workingDir.getName().length();
-			events.add(Integer.toString(dirLen));
-			events.add(inputBaclava == null ? "<null>" : inputBaclava
-					.toString().substring(dirLen));
-			Map<String, String> in = new TreeMap<>();
-			for (Entry<String, File> name : inputFiles.entrySet())
-				in.put(name.getKey(), name.getValue() == null ? "<null>" : name
-						.getValue().getName());
-			events.add(in.toString());
-			events.add(new TreeMap<>(inputValues).toString());
-			events.add(outputBaclava == null ? "<null>" : outputBaclava
-					.getName());
-			// TODO: check cmdir and cmpass
-			// TODO: check doprov
-			// TODO: log env
-			// TODO: check delimiters
-			events.add("]");
-			return true;
-		}
-
-		@Override
-		public void killWorker() throws Exception {
-			events.add("kill");
-		}
-
-		@Override
-		public void startWorker() throws Exception {
-			events.add("start");
-		}
-
-		@Override
-		public void stopWorker() throws Exception {
-			events.add("stop");
-		}
-
-		@Override
-		public void setURReceiver(UsageRecordReceiver receiver) {
-			// We just ignore this
-		}
-
-		@Override
-		public void deleteLocalResources() throws ImplementationException {
-			// Nothing to do here
-		}
-	}
-
-	WorkerFactory factory = new WorkerFactory() {
-		@Override
-		public Worker makeInstance() throws Exception {
-			return new DummyWorker();
-		}
-	};
-
-	@Before
-	public void setUp() throws Exception {
-		lw = new LocalWorker("XWC", "WF".getBytes("UTF-8"), null, randomUUID(),
-				new HashMap<String, String>(), new ArrayList<String>(), factory);
-		events = new ArrayList<>();
-		returnThisStatus = RemoteStatus.Operating;
-	}
-
-	@After
-	public void tearDown() throws Exception {
-		lw.destroy();
-	}
-
-	private List<String> l(String... strings) {
-		return Arrays.asList(strings);
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	@Test
-	public void testDestroy1() throws Exception {
-		lw.destroy();
-		assertEquals(l(), events);
-	}
-
-	@Test
-	public void testDestroy2() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.destroy();
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "kill"), events);
-	}
-
-	@Test
-	public void testDestroy3() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.destroy();
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "stop", "kill"), events);
-	}
-
-	@Test
-	public void testDestroy4() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Finished);
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "kill"), events);
-		lw.destroy();
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "kill"), events);
-	}
-
-	@Test
-	public void testAddListener() {
-		Throwable t = null;
-		try {
-			lw.addListener(null);
-		} catch (Throwable caught) {
-			t = caught;
-		}
-		assertNotNull(t);
-		assertSame(ImplementationException.class, t.getClass());
-		assertNotNull(t.getMessage());
-		assertEquals("not implemented", t.getMessage());
-	}
-
-	@Test
-	public void testGetInputBaclavaFile() throws Exception {
-		assertNull(lw.getInputBaclavaFile());
-		lw.setInputBaclavaFile("IBaclava");
-		assertNotNull(lw.getInputBaclavaFile());
-		assertEquals("IBaclava", lw.getInputBaclavaFile());
-		lw.makeInput("FOO").setValue("BAR");
-		assertNull(lw.getInputBaclavaFile());
-	}
-
-	@Test
-	public void testGetInputsWithValue() throws Exception {
-		assertEquals(0, lw.getInputs().size());
-
-		lw.makeInput("FOO").setValue("BAR");
-
-		assertEquals(1, lw.getInputs().size());
-		assertEquals("FOO", lw.getInputs().get(0).getName());
-		assertNull(lw.getInputs().get(0).getFile());
-		assertNotNull(lw.getInputs().get(0).getValue());
-
-		lw.setInputBaclavaFile("BLAH");
-
-		assertEquals(1, lw.getInputs().size());
-		assertNull(lw.getInputs().get(0).getFile());
-		assertNull(lw.getInputs().get(0).getValue());
-	}
-
-	@Test
-	public void testGetInputsWithFile() throws Exception {
-		assertEquals(0, lw.getInputs().size());
-
-		lw.makeInput("BAR").setFile("FOO");
-
-		assertEquals(1, lw.getInputs().size());
-		assertEquals("BAR", lw.getInputs().get(0).getName());
-		assertNotNull(lw.getInputs().get(0).getFile());
-		assertNull(lw.getInputs().get(0).getValue());
-
-		lw.setInputBaclavaFile("BLAH");
-
-		assertEquals(1, lw.getInputs().size());
-		assertNull(lw.getInputs().get(0).getFile());
-		assertNull(lw.getInputs().get(0).getValue());
-	}
-
-	@Test
-	public void testGetListenerTypes() {
-		assertEquals("[]", lw.getListenerTypes().toString());
-	}
-
-	@Test
-	public void testGetListeners() throws Exception {
-		assertEquals(1, lw.getListeners().size());
-		RemoteListener rl = lw.getListeners().get(0);
-		assertEquals("RLNAME", rl.getName());
-		assertEquals("RLCONFIG", rl.getConfiguration());
-		assertEquals("RLTYPE", rl.getType());
-		assertEquals("[RLP1, RLP2]", Arrays.asList(rl.listProperties())
-				.toString());
-		assertEquals("RLPROP[RLP1]", rl.getProperty("RLP1"));
-		assertEquals("RLPROP[RLP2]", rl.getProperty("RLP2"));
-		rl.setProperty("FOOBAR", "BARFOO");
-		assertEquals(l("setProperty[", "FOOBAR", "BARFOO", "]"), events);
-	}
-
-	@Test
-	public void testGetOutputBaclavaFile() throws Exception {
-		assertNull(lw.getOutputBaclavaFile());
-		lw.setOutputBaclavaFile("notnull");
-		assertEquals("notnull", lw.getOutputBaclavaFile());
-		lw.setOutputBaclavaFile(null);
-		assertNull(lw.getOutputBaclavaFile());
-	}
-
-	@Test
-	public void testGetSecurityContext() throws Exception {
-		boolean md = DO_MKDIR;
-		LocalWorker.DO_MKDIR = false; // HACK! Work around Hudson problem...
-		try {
-			assertNotNull(lw.getSecurityContext());
-		} finally {
-			LocalWorker.DO_MKDIR = md;
-		}
-	}
-
-	@Test
-	public void testGetStatusInitial() {
-		assertEquals(RemoteStatus.Initialized, lw.getStatus());
-	}
-
-	@Test
-	public void testGetStatus() throws Exception {
-		assertEquals(RemoteStatus.Initialized, lw.getStatus());
-		returnThisStatus = RemoteStatus.Operating;
-		assertEquals(RemoteStatus.Initialized, lw.getStatus());
-		lw.setStatus(RemoteStatus.Operating);
-		assertEquals(RemoteStatus.Operating, lw.getStatus());
-		assertEquals(RemoteStatus.Operating, lw.getStatus());
-		returnThisStatus = RemoteStatus.Finished;
-		assertEquals(RemoteStatus.Finished, lw.getStatus());
-		returnThisStatus = RemoteStatus.Stopped;
-		assertEquals(RemoteStatus.Finished, lw.getStatus());
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "status=Operating", "status=Operating",
-						"status=Finished"), events);
-	}
-
-	@Test
-	public void testGetWorkingDirectory() throws Exception {
-		RemoteDirectory rd = lw.getWorkingDirectory();
-		assertNotNull(rd);
-		assertNotNull(rd.getContents());
-		assertNull(rd.getContainingDirectory());
-		assertNotNull(rd.getName());
-		assertEquals(-1, rd.getName().indexOf('/'));
-		assertFalse("..".equals(rd.getName()));
-		assertEquals("", rd.getName());
-	}
-
-	@Test
-	public void testValidateFilename() throws Exception {
-		lw.validateFilename("foobar");
-		lw.validateFilename("foo/bar");
-		lw.validateFilename("foo.bar");
-		lw.validateFilename("foo..bar");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad0() throws Exception {
-		lw.validateFilename("./.");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad1() throws Exception {
-		lw.validateFilename("/");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad2() throws Exception {
-		lw.validateFilename("");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad3() throws Exception {
-		lw.validateFilename(null);
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad4() throws Exception {
-		lw.validateFilename("..");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad5() throws Exception {
-		lw.validateFilename("foo/../bar");
-	}
-
-	@Test
-	public void testMakeInput() throws Exception {
-		assertEquals(0, lw.getInputs().size());
-
-		RemoteInput ri = lw.makeInput("TEST");
-
-		assertNotNull(ri);
-		assertEquals(1, lw.getInputs().size());
-		assertNotSame(ri, lw.getInputs().get(0)); // different delegates
-		assertEquals("TEST", ri.getName());
-		assertNull(ri.getFile());
-		assertNull(ri.getValue());
-
-		lw.setInputBaclavaFile("bad");
-		ri.setFile("good");
-		assertEquals("good", ri.getFile());
-		assertNull(lw.getInputBaclavaFile());
-		ri.setValue("very good");
-		assertEquals("very good", ri.getValue());
-		assertNull(ri.getFile());
-		assertNull(lw.getInputBaclavaFile());
-
-		lw.makeInput("TEST2");
-		assertEquals(2, lw.getInputs().size());
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testMakeInputFileSanity() throws Exception {
-		lw.makeInput("foo").setFile("/../bar");
-	}
-
-	@Test
-	public void testMakeListener() {
-		Throwable t = null;
-		try {
-			lw.makeListener("?", "?");
-		} catch (Throwable caught) {
-			t = caught;
-		}
-		assertNotNull(t);
-		assertSame(RemoteException.class, t.getClass());
-		assertNotNull(t.getMessage());
-		assertEquals("listener manufacturing unsupported", t.getMessage());
-	}
-
-	@Test
-	public void testSetInputBaclavaFile1() throws Exception {
-		assertNull(lw.getInputBaclavaFile());
-		lw.setInputBaclavaFile("eg");
-		assertEquals("eg", lw.getInputBaclavaFile());
-	}
-
-	@Test
-	public void testSetInputBaclavaFile2() throws Exception {
-		RemoteInput ri = lw.makeInput("foo");
-		ri.setValue("bar");
-		assertEquals("bar", ri.getValue());
-		lw.setInputBaclavaFile("eg");
-		assertNull(ri.getValue());
-	}
-
-	@Test
-	public void testSetOutputBaclavaFile1() throws Exception {
-		assertNull(lw.outputBaclava);
-		lw.setOutputBaclavaFile("foobar");
-		assertEquals("foobar", lw.outputBaclava);
-		assertEquals("foobar", lw.getOutputBaclavaFile());
-		lw.setOutputBaclavaFile("foo/bar");
-		assertEquals("foo/bar", lw.outputBaclava);
-		assertEquals("foo/bar", lw.getOutputBaclavaFile());
-		lw.setOutputBaclavaFile(null);
-		assertNull(lw.outputBaclava);
-		assertNull(lw.getOutputBaclavaFile());
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testSetOutputBaclavaFile2() throws Exception {
-		lw.setOutputBaclavaFile("/foobar");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testSetOutputBaclavaFile3() throws Exception {
-		lw.setOutputBaclavaFile("foo/../bar");
-	}
-
-	@Test
-	public void testSetStatus0() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Finished);
-		lw.setStatus(RemoteStatus.Finished);
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "stop", "start", "kill"), events);
-	}
-
-	@Test
-	public void testSetStatus1() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.setStatus(RemoteStatus.Finished);
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "stop", "kill"), events);
-	}
-
-	@Test
-	public void testSetStatus2() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Finished);
-		assertEquals(l(), events);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus3() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Finished);
-		lw.setStatus(RemoteStatus.Initialized);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus4() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Initialized);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus5() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Stopped);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus6() throws Exception {
-		lw.setStatus(RemoteStatus.Finished);
-		lw.setStatus(RemoteStatus.Stopped);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus7() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.setStatus(RemoteStatus.Initialized);
-	}
-
-	@Test
-	public void testLifecycle() throws Exception {
-		lw.makeInput("foo").setFile("foofile");
-		lw.makeInput("bar").setValue("barvalue");
-		lw.setOutputBaclavaFile("spong");
-		lw.setOutputBaclavaFile("boo");
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Finished);
-		// Assumes order of map, so fragile but works...
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>",
-						"{bar=<null>, foo=foofile}",
-						"{bar=barvalue, foo=null}", "boo", "]", "kill"), events);
-	}
-}


[40/42] incubator-taverna-server git commit: package org.apache.taverna.server.*

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCredentialException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCredentialException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCredentialException.java
index b351c1c..63d44da 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCredentialException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCredentialException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDestroyException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDestroyException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDestroyException.java
index 42de7d1..f0263f8 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDestroyException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDestroyException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDirectoryEntryException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDirectoryEntryException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDirectoryEntryException.java
index 32300d1..9524e87 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDirectoryEntryException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDirectoryEntryException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoListenerException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoListenerException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoListenerException.java
index ef84e9e..c8762be 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoListenerException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoListenerException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoUpdateException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoUpdateException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoUpdateException.java
index 5e972dd..e73f9bd 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoUpdateException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoUpdateException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NotOwnerException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NotOwnerException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NotOwnerException.java
index 29e00b7..67de956 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NotOwnerException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NotOwnerException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/OverloadedException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/OverloadedException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/OverloadedException.java
index bd34659..15ac4bd 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/OverloadedException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/OverloadedException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/UnknownRunException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/UnknownRunException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/UnknownRunException.java
index af717ab..fe24079 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/UnknownRunException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/UnknownRunException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/package-info.java
index b2284ee..5070efa 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/package-info.java
@@ -11,7 +11,7 @@
 		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
 		@XmlNs(prefix = "feed", namespaceURI = FEED),
 		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -30,12 +30,12 @@ package org.taverna.server.master.exceptions;
  */
 
 import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Namespaces.ADMIN;
+import static org.apache.taverna.server.master.common.Namespaces.FEED;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.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/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/Facade.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/Facade.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/Facade.java
index 3031520..10c92e8 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/Facade.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/Facade.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.facade;
+package org.apache.taverna.server.master.facade;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -35,7 +35,7 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.utils.Contextualizer;
+import org.apache.taverna.server.master.utils.Contextualizer;
 
 /**
  * This is a simple class that is used to serve up a file (with a simple

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/package-info.java
index 2d8f4ef..b26ef30 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/package-info.java
@@ -4,7 +4,7 @@
  * Simple facade used at the top level of the Taverna Server in order to
  * provide an entry splash page.
  */
-package org.taverna.server.master.facade;
+package org.apache.taverna.server.master.facade;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ConfigurableRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ConfigurableRunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ConfigurableRunFactory.java
index 7a4124d..3e5e67b 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ConfigurableRunFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ConfigurableRunFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.factories;
+package org.apache.taverna.server.master.factories;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ListenerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ListenerFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ListenerFactory.java
index bb83401..90f0daa 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ListenerFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ListenerFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.factories;
+package org.apache.taverna.server.master.factories;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,9 +20,9 @@ package org.taverna.server.master.factories;
 
 import java.util.List;
 
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
 
 /**
  * How to make event listeners of various types that are attached to a workflow

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/RunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/RunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/RunFactory.java
index d048f70..23b9d96 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/RunFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/RunFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.factories;
+package org.apache.taverna.server.master.factories;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,10 +18,10 @@ package org.taverna.server.master.factories;
  * limitations under the License.
  */
 
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * How to construct a Taverna Server Workflow Run.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/package-info.java
index 56ba1e2..e6fed2d 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/package-info.java
@@ -4,7 +4,7 @@
  * These interfaces define the principal way for the <i>factories</i> of
  * worker classes to be invoked.
  */
-package org.taverna.server.master.factories;
+package org.apache.taverna.server.master.factories;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/AuthorityDerivedIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/AuthorityDerivedIDMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/AuthorityDerivedIDMapper.java
index 4fd5312..e3d4200 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/AuthorityDerivedIDMapper.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/AuthorityDerivedIDMapper.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,13 +18,13 @@ package org.taverna.server.master.identity;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
+import static org.apache.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
 
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * Extracts the local user id from the set of Spring Security authorities

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/CompositeIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/CompositeIDMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/CompositeIDMapper.java
index f0a6f4c..ca3e37a 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/CompositeIDMapper.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/CompositeIDMapper.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -27,8 +27,8 @@ import org.apache.commons.logging.Log;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * An identity mapper that composes the results from other mappers, using the

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/ConstantIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/ConstantIDMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/ConstantIDMapper.java
index bf48fc7..1481ef9 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/ConstantIDMapper.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/ConstantIDMapper.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,8 +18,8 @@ package org.taverna.server.master.identity;
  * limitations under the License.
  */
 
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * A trivial principal to user mapper that always uses the same ID.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/NameIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/NameIDMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/NameIDMapper.java
index 9d11cfd..dbead86 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/NameIDMapper.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/NameIDMapper.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,8 +25,8 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * A trivial identity mapper that just uses the name out of the

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/StrippedDownAuthProvider.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/StrippedDownAuthProvider.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/StrippedDownAuthProvider.java
index dc489ae..39c1435 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/StrippedDownAuthProvider.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/StrippedDownAuthProvider.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -38,7 +38,7 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.crypto.password.PasswordEncoder;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
 
 /**
  * A stripped down version of a

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/User.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/User.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/User.java
index 1fdf2bf..dafdf13 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/User.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/User.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,9 +18,9 @@ package org.taverna.server.master.identity;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
+import static org.apache.taverna.server.master.common.Roles.ADMIN;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
 
 import java.util.ArrayList;
 import java.util.Collection;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStore.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStore.java
index 3177d5c..3c70ea6 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStore.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStore.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,10 +19,10 @@ package org.taverna.server.master.identity;
  */
 
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
+import static org.apache.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.apache.taverna.server.master.common.Roles.ADMIN;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -50,8 +50,8 @@ import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.core.userdetails.memory.UserAttribute;
 import org.springframework.security.core.userdetails.memory.UserAttributeEditor;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.JDOSupport;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.JDOSupport;
 
 /**
  * The bean class that is responsible for managing the users in the database.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStoreAPI.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStoreAPI.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStoreAPI.java
index c4caf3c..aff3fa5 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStoreAPI.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStoreAPI.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/WorkflowInternalAuthProvider.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/WorkflowInternalAuthProvider.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/WorkflowInternalAuthProvider.java
index c733d89..2a184ae 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/WorkflowInternalAuthProvider.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/WorkflowInternalAuthProvider.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,7 +20,7 @@ package org.taverna.server.master.identity;
 
 import static java.util.Collections.synchronizedMap;
 import static org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes;
-import static org.taverna.server.master.common.Roles.SELF;
+import static org.apache.taverna.server.master.common.Roles.SELF;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -51,12 +51,12 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.security.web.authentication.WebAuthenticationDetails;
 import org.springframework.web.context.request.ServletRequestAttributes;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.worker.RunDatabaseDAO;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.apache.taverna.server.master.interfaces.RunStore;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.worker.RunDatabaseDAO;
 
 /**
  * A special authentication provider that allows a workflow to authenticate to

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/package-info.java
index 14ad7db..17c525e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/package-info.java
@@ -4,7 +4,7 @@
  * Implementations of beans that map global user identities to local
  * usernames.
  */
-package org.taverna.server.master.identity;
+package org.apache.taverna.server.master.identity;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/InteractionFeedSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/InteractionFeedSupport.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/InteractionFeedSupport.java
index 4b297dc..7ec09ba 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/InteractionFeedSupport.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/InteractionFeedSupport.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interaction;
+package org.apache.taverna.server.master.interaction;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -52,16 +52,16 @@ import org.apache.abdera.model.Feed;
 import org.apache.abdera.parser.Parser;
 import org.apache.abdera.writer.Writer;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.TavernaServerSupport;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.master.TavernaServerSupport;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.interfaces.DirectoryEntry;
+import org.apache.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.UriBuilderFactory;
+import org.apache.taverna.server.master.utils.FilenameUtils;
 
 /**
  * Bean that supports interaction feeds. This glues together the Abdera

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/package-info.java
index 54ec630..8870b56 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/package-info.java
@@ -4,7 +4,7 @@
  * This package contains the Atom feed implementation for interactions for a particular workflow run.
  * @author Donal Fellows
  */
-package org.taverna.server.master.interaction;
+package org.apache.taverna.server.master.interaction;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Directory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Directory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Directory.java
index bb74f5a..17ed631 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Directory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Directory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,7 +22,7 @@ import java.io.PipedInputStream;
 import java.security.Principal;
 import java.util.Collection;
 
-import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
 
 /**
  * Represents a directory that is the working directory of a workflow run, or a

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/DirectoryEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/DirectoryEntry.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/DirectoryEntry.java
index e1a0865..f3f10c6 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/DirectoryEntry.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/DirectoryEntry.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,7 +20,7 @@ package org.taverna.server.master.interfaces;
 
 import java.util.Date;
 
-import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
 
 /**
  * An entry in a {@link Directory} representing a file or sub-directory.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/File.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/File.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/File.java
index 97510e4..baef235 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/File.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/File.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.interfaces;
  * limitations under the License.
  */
 
-import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
 
 /**
  * Represents a file in the working directory of a workflow instance run, or in

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Input.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Input.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Input.java
index 5d92f67..1a797b4 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Input.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Input.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,9 +21,9 @@ package org.taverna.server.master.interfaces;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
 
 /**
  * This represents the assignment of inputs to input ports of the workflow. Note

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Listener.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Listener.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Listener.java
index 5fee6cc..e58d630 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Listener.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Listener.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,8 +18,8 @@ package org.taverna.server.master.interfaces;
  * limitations under the License.
  */
 
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.BadPropertyValueException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
 
 /**
  * An event listener that can be attached to a {@link TavernaRun}.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/LocalIdentityMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/LocalIdentityMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/LocalIdentityMapper.java
index becc55c..6e8bdef 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/LocalIdentityMapper.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/LocalIdentityMapper.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.interfaces;
  * limitations under the License.
  */
 
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * This interface describes how to map from the identity understood by the

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/MessageDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/MessageDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/MessageDispatcher.java
index b3e0260..8062c62 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/MessageDispatcher.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/MessageDispatcher.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Policy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Policy.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Policy.java
index b09e0bd..295b38e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Policy.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Policy.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,12 +21,12 @@ package org.taverna.server.master.interfaces;
 import java.net.URI;
 import java.util.List;
 
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoDestroyException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * Simple policy interface.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/RunStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/RunStore.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/RunStore.java
index b0d817a..ded55e4 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/RunStore.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/RunStore.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,8 +20,8 @@ package org.taverna.server.master.interfaces;
 
 import java.util.Map;
 
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * Interface to the mechanism that looks after the mapping of names to runs.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/SecurityContextFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/SecurityContextFactory.java
index a0cac79..0f0b702 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/SecurityContextFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/SecurityContextFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,7 +20,7 @@ package org.taverna.server.master.interfaces;
 
 import java.io.Serializable;
 
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * How to create instances of a security context.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaRun.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaRun.java
index 8d9a7f8..cf2094e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaRun.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaRun.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,12 +22,12 @@ import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDestroyException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
 
 /**
  * The interface to a taverna workflow run, or "run" for short.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaSecurityContext.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaSecurityContext.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaSecurityContext.java
index 3f993df..9af5593 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaSecurityContext.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaSecurityContext.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -27,11 +27,11 @@ import javax.ws.rs.core.HttpHeaders;
 import javax.xml.ws.handler.MessageContext;
 
 import org.springframework.security.core.context.SecurityContext;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.localworker.remote.ImplementationException;
+import org.apache.taverna.server.master.common.Credential;
+import org.apache.taverna.server.master.common.Trust;
+import org.apache.taverna.server.master.exceptions.InvalidCredentialException;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * Security context for a workflow run.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/UriBuilderFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/UriBuilderFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/UriBuilderFactory.java
index c4d0fb5..eda2f7d 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/UriBuilderFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/UriBuilderFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/package-info.java
index 9c9b5b8..4e3b0d4 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/package-info.java
@@ -4,7 +4,7 @@
  * Interfaces to the main worker classes that provide the magical power
  * that drives the webapp front-end.
  */
-package org.taverna.server.master.interfaces;
+package org.apache.taverna.server.master.interfaces;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/AbstractRemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/AbstractRemoteRunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/AbstractRemoteRunFactory.java
index 72004b4..06f4dff 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/AbstractRemoteRunFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/AbstractRemoteRunFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.localworker;
+package org.apache.taverna.server.master.localworker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,8 +25,8 @@ import static java.rmi.registry.LocateRegistry.createRegistry;
 import static java.rmi.registry.LocateRegistry.getRegistry;
 import static java.rmi.registry.Registry.REGISTRY_PORT;
 import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
+import static org.apache.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
 
 import java.io.IOException;
 import java.io.ObjectInputStream;
@@ -51,25 +51,25 @@ import org.apache.commons.io.IOUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.factories.RunFactory;
-import org.taverna.server.master.interaction.InteractionFeedSupport;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.notification.atom.EventDAO;
-import org.taverna.server.master.usage.UsageRecordRecorder;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.worker.FactoryBean;
-import org.taverna.server.master.worker.RemoteRunDelegate;
-import org.taverna.server.master.worker.RunFactoryConfiguration;
+import org.apache.taverna.server.localworker.remote.RemoteRunFactory;
+import org.apache.taverna.server.localworker.remote.RemoteSingleRun;
+import org.apache.taverna.server.localworker.server.UsageRecordReceiver;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.factories.ListenerFactory;
+import org.apache.taverna.server.master.factories.RunFactory;
+import org.apache.taverna.server.master.interaction.InteractionFeedSupport;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.SecurityContextFactory;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.UriBuilderFactory;
+import org.apache.taverna.server.master.notification.atom.EventDAO;
+import org.apache.taverna.server.master.usage.UsageRecordRecorder;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.worker.FactoryBean;
+import org.apache.taverna.server.master.worker.RemoteRunDelegate;
+import org.apache.taverna.server.master.worker.RunFactoryConfiguration;
 
 import org.apache.taverna.scufl2.api.io.WriterException;
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/ForkRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/ForkRunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/ForkRunFactory.java
index 3f48644..9c2031f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/ForkRunFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/ForkRunFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.localworker;
+package org.apache.taverna.server.master.localworker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@ import static java.lang.Thread.sleep;
 import static java.util.Arrays.asList;
 import static java.util.Calendar.SECOND;
 import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.apache.taverna.server.master.TavernaServer.JMX_ROOT;
 
 import java.io.File;
 import java.rmi.ConnectException;
@@ -40,12 +40,12 @@ import javax.xml.bind.JAXBException;
 
 import org.springframework.jmx.export.annotation.ManagedAttribute;
 import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.localworker.remote.RemoteRunFactory;
+import org.apache.taverna.server.localworker.remote.RemoteSingleRun;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.factories.ConfigurableRunFactory;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * A simple factory for workflow runs that forks runs from a subprocess.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/IdAwareForkRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/IdAwareForkRunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/IdAwareForkRunFactory.java
index a2e5ff7..ca6ed3a 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/IdAwareForkRunFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/IdAwareForkRunFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.localworker;
+package org.apache.taverna.server.master.localworker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,8 +23,8 @@ import static java.lang.Thread.sleep;
 import static java.util.Arrays.asList;
 import static java.util.Calendar.SECOND;
 import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.localworker.AbstractRemoteRunFactory.launchSubprocess;
+import static org.apache.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.apache.taverna.server.master.localworker.AbstractRemoteRunFactory.launchSubprocess;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -55,13 +55,13 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.core.annotation.Order;
 import org.springframework.jmx.export.annotation.ManagedAttribute;
 import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.localworker.remote.RemoteRunFactory;
+import org.apache.taverna.server.localworker.remote.RemoteSingleRun;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.factories.ConfigurableRunFactory;
+import org.apache.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * A simple factory for workflow runs that forks runs from a subprocess.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerFactory.java
index 803c201..8509b0a 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.localworker;
+package org.apache.taverna.server.master.localworker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerState.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerState.java
index e32dcca..7df1e3b 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerState.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerState.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.localworker;
+package org.apache.taverna.server.master.localworker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,18 +24,18 @@ import static java.rmi.registry.Registry.REGISTRY_PORT;
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
 import static java.util.Collections.unmodifiableList;
-import static org.taverna.server.master.defaults.Default.EXTRA_ARGUMENTS;
-import static org.taverna.server.master.defaults.Default.PASSWORD_FILE;
-import static org.taverna.server.master.defaults.Default.REGISTRY_JAR;
-import static org.taverna.server.master.defaults.Default.RMI_PREFIX;
-import static org.taverna.server.master.defaults.Default.RUN_LIFE_MINUTES;
-import static org.taverna.server.master.defaults.Default.RUN_OPERATING_LIMIT;
-import static org.taverna.server.master.defaults.Default.SECURE_FORK_IMPLEMENTATION_JAR;
-import static org.taverna.server.master.defaults.Default.SERVER_WORKER_IMPLEMENTATION_JAR;
-import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_POLL_SLEEP;
-import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_WAIT;
-import static org.taverna.server.master.localworker.PersistedState.KEY;
-import static org.taverna.server.master.localworker.PersistedState.makeInstance;
+import static org.apache.taverna.server.master.defaults.Default.EXTRA_ARGUMENTS;
+import static org.apache.taverna.server.master.defaults.Default.PASSWORD_FILE;
+import static org.apache.taverna.server.master.defaults.Default.REGISTRY_JAR;
+import static org.apache.taverna.server.master.defaults.Default.RMI_PREFIX;
+import static org.apache.taverna.server.master.defaults.Default.RUN_LIFE_MINUTES;
+import static org.apache.taverna.server.master.defaults.Default.RUN_OPERATING_LIMIT;
+import static org.apache.taverna.server.master.defaults.Default.SECURE_FORK_IMPLEMENTATION_JAR;
+import static org.apache.taverna.server.master.defaults.Default.SERVER_WORKER_IMPLEMENTATION_JAR;
+import static org.apache.taverna.server.master.defaults.Default.SUBPROCESS_START_POLL_SLEEP;
+import static org.apache.taverna.server.master.defaults.Default.SUBPROCESS_START_WAIT;
+import static org.apache.taverna.server.master.localworker.PersistedState.KEY;
+import static org.apache.taverna.server.master.localworker.PersistedState.makeInstance;
 
 import java.io.File;
 import java.io.FilenameFilter;
@@ -46,10 +46,10 @@ import javax.annotation.PostConstruct;
 import javax.jdo.annotations.PersistenceAware;
 
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.defaults.Default;
-import org.taverna.server.master.utils.JDOSupport;
-import org.taverna.server.master.worker.WorkerModel;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.defaults.Default;
+import org.apache.taverna.server.master.utils.JDOSupport;
+import org.apache.taverna.server.master.worker.WorkerModel;
 
 /**
  * The persistent state of a local worker factory.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/PersistedState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/PersistedState.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/PersistedState.java
index 3ed4c51..b36e4ca 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/PersistedState.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/PersistedState.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.localworker;
+package org.apache.taverna.server.master.localworker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -27,7 +27,7 @@ import javax.jdo.annotations.PersistenceCapable;
 import javax.jdo.annotations.Persistent;
 import javax.jdo.annotations.PrimaryKey;
 
-import org.taverna.server.master.worker.WorkerModel;
+import org.apache.taverna.server.master.worker.WorkerModel;
 
 /**
  * The actual database connector for persisted local worker state.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/StreamLogger.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/StreamLogger.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/StreamLogger.java
index e563965..c34764e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/StreamLogger.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/StreamLogger.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.localworker;
+package org.apache.taverna.server.master.localworker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/package-info.java
index 031ce34..34c22c5 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/package-info.java
@@ -4,7 +4,7 @@
  * Implementation of a Taverna Server back-end that works by forking off
  * workflow executors on the local system.
  */
-package org.taverna.server.master.localworker;
+package org.apache.taverna.server.master.localworker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/EmailDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/EmailDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/EmailDispatcher.java
index 2a51496..6ea2ba6 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/EmailDispatcher.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/EmailDispatcher.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.notification;
+package org.apache.taverna.server.master.notification;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/JabberDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/JabberDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/JabberDispatcher.java
index 711f4e6..f08aebe 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/JabberDispatcher.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/JabberDispatcher.java
@@ -1,7 +1,7 @@
 /*
  */
 
-package org.taverna.server.master.notification;
+package org.apache.taverna.server.master.notification;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -29,8 +29,8 @@ import org.jivesoftware.smack.ConnectionConfiguration;
 import org.jivesoftware.smack.MessageListener;
 import org.jivesoftware.smack.XMPPConnection;
 import org.jivesoftware.smack.packet.Message;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.MessageDispatcher;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
 
 /**
  * Send notifications by Jabber/XMPP.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/NotificationEngine.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/NotificationEngine.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/NotificationEngine.java
index 067d154..8017524 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/NotificationEngine.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/NotificationEngine.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.notification;
+package org.apache.taverna.server.master.notification;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -28,8 +28,8 @@ import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.MessageDispatcher;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
 
 /**
  * A common object for handling dispatch of event-driven messages.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/RateLimitedDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/RateLimitedDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/RateLimitedDispatcher.java
index a41e23b..6a2a585 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/RateLimitedDispatcher.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/RateLimitedDispatcher.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.notification;
+package org.apache.taverna.server.master.notification;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,8 +24,8 @@ import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.joda.time.DateTime;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.MessageDispatcher;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
 
 /**
  * Rate-limiting support. Some message fabrics simply should not be used to send

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/SMSDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/SMSDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/SMSDispatcher.java
index 559f111..f121619 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/SMSDispatcher.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/SMSDispatcher.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.notification;
+package org.apache.taverna.server.master.notification;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.notification;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.defaults.Default.SMS_GATEWAY_URL;
+import static org.apache.taverna.server.master.defaults.Default.SMS_GATEWAY_URL;
 
 import java.io.BufferedReader;
 import java.io.IOException;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/TwitterDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/TwitterDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/TwitterDispatcher.java
index a0269a5..2bdd246 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/TwitterDispatcher.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/TwitterDispatcher.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.notification;
+package org.apache.taverna.server.master.notification;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/AtomFeed.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/AtomFeed.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/AtomFeed.java
index eda6d9d..3d78cae 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/AtomFeed.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/AtomFeed.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.notification.atom;
+package org.apache.taverna.server.master.notification.atom;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,8 +21,8 @@ package org.taverna.server.master.notification.atom;
 import static java.lang.String.format;
 import static java.util.UUID.randomUUID;
 import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.common.Uri.secure;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.common.Uri.secure;
 
 import java.net.URI;
 import java.util.Date;
@@ -37,11 +37,11 @@ import org.apache.abdera.model.Entry;
 import org.apache.abdera.model.Feed;
 import org.springframework.beans.factory.annotation.Required;
 import org.springframework.web.context.ServletContextAware;
-import org.taverna.server.master.TavernaServerSupport;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.rest.TavernaServerREST.EventFeed;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.master.TavernaServerSupport;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.UriBuilderFactory;
+import org.apache.taverna.server.master.rest.TavernaServerREST.EventFeed;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
 
 /**
  * Simple REST handler that allows an Atom feed to be served up of events

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/Event.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/Event.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/Event.java
index f1a9d62..45e6767 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/Event.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/Event.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.notification.atom;
+package org.apache.taverna.server.master.notification.atom;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -34,7 +34,7 @@ import javax.jdo.annotations.Query;
 import org.apache.abdera.Abdera;
 import org.apache.abdera.model.Entry;
 import org.joda.time.DateTime;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * Parent class of all events that may appear on the feed for a workflow run.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/EventDAO.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/EventDAO.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/EventDAO.java
index 8bec456..dd49c91 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/EventDAO.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/EventDAO.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.notification.atom;
+package org.apache.taverna.server.master.notification.atom;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -37,11 +37,11 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.joda.time.DateTime;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.JDOSupport;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.interfaces.MessageDispatcher;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.UriBuilderFactory;
+import org.apache.taverna.server.master.utils.JDOSupport;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * The database interface that supports the event feed.



[13/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java
deleted file mode 100644
index 72004b4..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- */
-package org.taverna.server.master.localworker;
-/*
- * 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.
- */
-
-import static java.lang.System.getSecurityManager;
-import static java.lang.System.setProperty;
-import static java.lang.System.setSecurityManager;
-import static java.rmi.registry.LocateRegistry.createRegistry;
-import static java.rmi.registry.LocateRegistry.getRegistry;
-import static java.rmi.registry.Registry.REGISTRY_PORT;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.net.URI;
-import java.net.URL;
-import java.rmi.MarshalledObject;
-import java.rmi.RemoteException;
-import java.rmi.registry.LocateRegistry;
-import java.rmi.registry.Registry;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.UUID;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.Resource;
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.io.IOUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.factories.RunFactory;
-import org.taverna.server.master.interaction.InteractionFeedSupport;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.notification.atom.EventDAO;
-import org.taverna.server.master.usage.UsageRecordRecorder;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.worker.FactoryBean;
-import org.taverna.server.master.worker.RemoteRunDelegate;
-import org.taverna.server.master.worker.RunFactoryConfiguration;
-
-import org.apache.taverna.scufl2.api.io.WriterException;
-
-/**
- * Bridge to remote runs via RMI.
- * 
- * @author Donal Fellows
- */
-@ManagedResource(objectName = JMX_ROOT + "Factory", description = "The factory for runs")
-public abstract class AbstractRemoteRunFactory extends RunFactoryConfiguration
-		implements ListenerFactory, RunFactory, FactoryBean {
-	/**
-	 * Whether to apply stronger limitations than normal to RMI. It is
-	 * recommended that this be true!
-	 */
-	@Value("${rmi.localhostOnly}")
-	private boolean rmiLocalhostOnly;
-	/** The interaction host name. */
-	private String interhost;
-	/** The interaction port number. */
-	private String interport;
-	private Process registryProcess;
-	/**
-	 * The interaction WebDAV location. Will be resolved before being passed to
-	 * the back-end.
-	 */
-	private String interwebdav;
-	/**
-	 * The interaction ATOM feed location. Will be resolved before being passed
-	 * to the back-end.
-	 */
-	private String interfeed;
-	/** Used for doing URI resolution. */
-	@Resource(name = "webapp")
-	private UriBuilderFactory baseurifactory;
-	@Autowired
-	private InteractionFeedSupport interactionFeedSupport;
-
-	@Value("${taverna.interaction.host}")
-	void setInteractionHost(String host) {
-		if (host != null && host.equals("none"))
-			host = null;
-		interhost = host;
-	}
-
-	@Value("${taverna.interaction.port}")
-	void setInteractionPort(String port) {
-		if (port != null && port.equals("none"))
-			port = null;
-		interport = port;
-	}
-
-	@Value("${taverna.interaction.webdav_path}")
-	void setInteractionWebdav(String webdav) {
-		if (webdav != null && webdav.equals("none"))
-			webdav = null;
-		interwebdav = webdav;
-	}
-
-	@Value("${taverna.interaction.feed_path}")
-	void setInteractionFeed(String feed) {
-		if (feed != null && feed.equals("none"))
-			feed = null;
-		interfeed = feed;
-	}
-
-	@Override
-	protected void reinitRegistry() {
-		registry = null;
-		if (registryProcess != null) {
-			registryProcess.destroy();
-			registryProcess = null;
-		}
-	}
-
-	protected void initInteractionDetails(RemoteRunFactory factory)
-			throws RemoteException {
-		if (interhost != null) {
-			String feed = baseurifactory.resolve(interfeed);
-			String webdav = baseurifactory.resolve(interwebdav);
-			factory.setInteractionServiceDetails(interhost, interport, webdav,
-					feed);
-		}
-	}
-
-	protected static final Process launchSubprocess(ProcessBuilder b)
-			throws IOException {
-		Thread t = Thread.currentThread();
-		ClassLoader ccl = t.getContextClassLoader();
-		try {
-			t.setContextClassLoader(null);
-			return b.start();
-		} finally {
-			t.setContextClassLoader(ccl);
-		}
-	}
-
-	/** Get a handle to a new instance of the RMI registry. */
-	private Registry makeRegistry(int port) throws RemoteException {
-		ProcessBuilder p = new ProcessBuilder(getJavaBinary());
-		p.command().add("-jar");
-		p.command().add(getRmiRegistryJar());
-		p.command().add(Integer.toString(port));
-		p.command().add(Boolean.toString(rmiLocalhostOnly));
-		try {
-			Process proc = launchSubprocess(p);
-			Thread.sleep(getSleepTime());
-			try {
-				if (proc.exitValue() == 0)
-					return null;
-				String error = IOUtils.toString(proc.getErrorStream());
-				throw new RemoteException(error);
-			} catch (IllegalThreadStateException ise) {
-				// Still running!
-			}
-			try (ObjectInputStream ois = new ObjectInputStream(
-					proc.getInputStream())) {
-				@SuppressWarnings("unchecked")
-				Registry r = ((MarshalledObject<Registry>) ois.readObject())
-						.get();
-				registryProcess = proc;
-				return r;
-			}
-		} catch (RemoteException e) {
-			throw e;
-		} catch (ClassNotFoundException e) {
-			throw new RemoteException("unexpected registry type", e);
-		} catch (IOException e) {
-			throw new RemoteException("unexpected IO problem with registry", e);
-		} catch (InterruptedException e) {
-			throw new RemoteException("unexpected interrupt");
-		}
-	}
-
-	/**
-	 * @return A handle to the current RMI registry.
-	 */
-	protected Registry getTheRegistry() {
-		try {
-			if (registry != null) {
-				registry.list();
-				return registry;
-			}
-		} catch (RemoteException e) {
-			log.warn("non-functioning existing registry handle", e);
-			registry = null;
-		}
-		try {
-			registry = getRegistry(getRegistryHost(), getRegistryPort());
-			registry.list();
-			return registry;
-		} catch (RemoteException e) {
-			log.warn("Failed to get working RMI registry handle.");
-			registry = null;
-			log.warn("Will build new registry, "
-					+ "but service restart ability is at risk.");
-			try {
-				registry = makeRegistry(getRegistryPort());
-				registry.list();
-				return registry;
-			} catch (RemoteException e2) {
-				log.error(
-						"failed to create local working RMI registry on port "
-								+ getRegistryPort(), e2);
-				log.info("original connection exception", e);
-			}
-		}
-		try {
-			registry = getRegistry(getRegistryHost(), REGISTRY_PORT);
-			registry.list();
-			return registry;
-		} catch (RemoteException e) {
-			log.warn("Failed to get working RMI registry handle on backup port.");
-			try {
-				registry = makeRegistry(REGISTRY_PORT);
-				registry.list();
-				return registry;
-			} catch (RemoteException e2) {
-				log.fatal(
-						"totally failed to get registry handle, even on fallback!",
-						e2);
-				log.info("original connection exception", e);
-				registry = null;
-				throw new RuntimeException("No RMI Registry Available");
-			}
-		}
-	}
-
-	private Registry registry;
-	/**
-	 * The name of the resource that describes the default security policy to
-	 * install.
-	 */
-	public static final String SECURITY_POLICY_FILE = "security.policy";
-	private SecurityContextFactory securityFactory;
-	UsageRecordRecorder usageRecordSink;
-	private EventDAO masterEventFeed;
-
-	@Autowired(required = true)
-	void setSecurityContextFactory(SecurityContextFactory factory) {
-		this.securityFactory = factory;
-	}
-
-	@Autowired(required = true)
-	void setMasterEventFeed(EventDAO masterEventFeed) {
-		this.masterEventFeed = masterEventFeed;
-	}
-
-	@Autowired(required = true)
-	void setUsageRecordSink(UsageRecordRecorder usageRecordSink) {
-		this.usageRecordSink = usageRecordSink;
-	}
-
-	/**
-	 * Configures the Java security model. Not currently used, as it is
-	 * viciously difficult to get right!
-	 */
-	@SuppressWarnings("unused")
-	private static void installSecurityManager() {
-		if (getSecurityManager() == null) {
-			setProperty("java.security.policy", AbstractRemoteRunFactory.class
-					.getClassLoader().getResource(SECURITY_POLICY_FILE)
-					.toExternalForm());
-			setSecurityManager(new SecurityManager());
-		}
-	}
-
-	// static {
-	// installSecurityManager();
-	// }
-
-	/**
-	 * Set up the run expiry management engine.
-	 * 
-	 * @throws JAXBException
-	 */
-	public AbstractRemoteRunFactory() throws JAXBException {
-		try {
-			registry = LocateRegistry.getRegistry();
-			registry.list();
-		} catch (RemoteException e) {
-			log.warn("Failed to get working RMI registry handle.");
-			log.warn("Will build new registry, but service restart ability is at risk.");
-			try {
-				registry = createRegistry(REGISTRY_PORT);
-				registry.list();
-			} catch (RemoteException e2) {
-				log.error("failed to create working RMI registry", e2);
-				log.info("original connection exception", e);
-			}
-		}
-	}
-
-	@Override
-	public List<String> getSupportedListenerTypes() {
-		try {
-			RemoteRunDelegate rrd = runDB.pickArbitraryRun();
-			if (rrd != null)
-				return rrd.getListenerTypes();
-			log.warn("no remote runs; no listener types");
-		} catch (Exception e) {
-			log.warn("failed to get list of listener types", e);
-		}
-		return new ArrayList<>();
-	}
-
-	@Override
-	public Listener makeListener(TavernaRun run, String listenerType,
-			String configuration) throws NoListenerException {
-		if (run instanceof RemoteRunDelegate)
-			return ((RemoteRunDelegate) run).makeListener(listenerType,
-					configuration);
-		throw new NoListenerException("unexpected run type: " + run.getClass());
-	}
-
-	@Override
-	public TavernaRun create(UsernamePrincipal creator, Workflow workflow)
-			throws NoCreateException {
-		try {
-			Date now = new Date();
-			UUID id = randomUUID();
-			RemoteSingleRun rsr = getRealRun(creator, workflow, id);
-			RemoteRunDelegate run = new RemoteRunDelegate(now, workflow, rsr,
-					state.getDefaultLifetime(), runDB, id,
-					state.getGenerateProvenance(), this);
-			run.setSecurityContext(securityFactory.create(run, creator));
-			@Nonnull
-			URI feed = interactionFeedSupport.getFeedURI(run);
-			@Nonnull
-			URL feedUrl = feed.toURL();
-			@Nonnull
-			URL webdavUrl = baseurifactory.getRunUriBuilder(run)
-					.path(DIR + "/interactions").build().toURL();
-			@Nullable
-			URL pub = interactionFeedSupport.getLocalFeedBase(feed);
-			rsr.setInteractionServiceDetails(feedUrl, webdavUrl, pub);
-			return run;
-		} catch (NoCreateException e) {
-			log.warn("failed to build run instance", e);
-			throw e;
-		} catch (Exception e) {
-			log.warn("failed to build run instance", e);
-			throw new NoCreateException("failed to build run instance", e);
-		}
-	}
-
-	/**
-	 * Gets the RMI connector for a new run.
-	 * 
-	 * @param creator
-	 *            Who is creating the workflow run.
-	 * @param workflow
-	 *            What workflow are they instantiating.
-	 * @param id
-	 *            The identity token for the run, newly minted.
-	 * @return The remote interface to the run.
-	 * @throws Exception
-	 *             Just about anything can go wrong...
-	 */
-	protected abstract RemoteSingleRun getRealRun(UsernamePrincipal creator,
-			Workflow workflow, UUID id) throws Exception;
-
-	/**
-	 * How to convert a wrapped workflow into XML.
-	 * 
-	 * @param workflow
-	 *            The wrapped workflow.
-	 * @return The XML version of the document.
-	 * @throws JAXBException
-	 *             If serialization fails.
-	 */
-	protected byte[] serializeWorkflow(Workflow workflow) throws JAXBException {
-		try {
-			return workflow.getScufl2Bytes();
-		} catch (IOException e) {
-			throw new JAXBException("problem converting to scufl2", e);
-		} catch (WriterException e) {
-			throw new JAXBException("problem converting to scufl2", e);
-		}
-	}
-
-	private void acceptUsageRecord(String usageRecord) {
-		if (usageRecordSink != null)
-			usageRecordSink.storeUsageRecord(usageRecord);
-		runDB.checkForFinishNow();
-	}
-
-	/**
-	 * Make a Remote object that can act as a consumer for usage records.
-	 * 
-	 * @param creator
-	 * 
-	 * @return The receiver, or <tt>null</tt> if the construction fails.
-	 */
-	protected UsageRecordReceiver makeURReciver(UsernamePrincipal creator) {
-		try {
-			@SuppressWarnings("serial")
-			class URReceiver extends UnicastRemoteObject implements
-					UsageRecordReceiver {
-				public URReceiver() throws RemoteException {
-					super();
-				}
-
-				@Override
-				public void acceptUsageRecord(String usageRecord) {
-					AbstractRemoteRunFactory.this.acceptUsageRecord(usageRecord);
-				}
-			}
-			return new URReceiver();
-		} catch (RemoteException e) {
-			log.warn("failed to build usage record receiver", e);
-			return null;
-		}
-	}
-
-	@Override
-	public EventDAO getMasterEventFeed() {
-		return masterEventFeed;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java
deleted file mode 100644
index 3f48644..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- */
-package org.taverna.server.master.localworker;
-/*
- * 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.
- */
-
-import static java.lang.System.getProperty;
-import static java.lang.Thread.sleep;
-import static java.util.Arrays.asList;
-import static java.util.Calendar.SECOND;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-
-import java.io.File;
-import java.rmi.ConnectException;
-import java.rmi.ConnectIOException;
-import java.rmi.NotBoundException;
-import java.rmi.RemoteException;
-import java.util.Calendar;
-import java.util.UUID;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.xml.bind.JAXBException;
-
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A simple factory for workflow runs that forks runs from a subprocess.
- * 
- * @author Donal Fellows
- */
-@ManagedResource(objectName = JMX_ROOT + "RunFactory", description = "The factory for simple singleton forked run.")
-public class ForkRunFactory extends AbstractRemoteRunFactory implements
-		ConfigurableRunFactory {
-	private int lastStartupCheckCount;
-	private Integer lastExitCode;
-	private RemoteRunFactory factory;
-	private Process factoryProcess;
-	private String factoryProcessName;
-
-	/**
-	 * Create a factory for remote runs that works by forking off a subprocess.
-	 * 
-	 * @throws JAXBException
-	 *             Shouldn't happen.
-	 */
-	public ForkRunFactory() throws JAXBException {
-	}
-
-	@PostConstruct
-	protected void initRegistry() {
-		log.info("waiting for availability of default RMI registry");
-		getTheRegistry();
-	}
-
-	@Override
-	protected void reinitFactory() {
-		boolean makeFactory = factory != null;
-		killFactory();
-		try {
-			if (makeFactory)
-				initFactory();
-		} catch (Exception e) {
-			log.fatal("failed to make connection to remote run factory", e);
-		}
-	}
-
-	private RemoteRunFactory getFactory() throws RemoteException {
-		try {
-			initFactory();
-		} catch (RemoteException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new RemoteException("problem constructing factory", e);
-		}
-		return factory;
-	}
-
-	/**
-	 * @return How many checks were done for the worker process the last time a
-	 *         spawn was tried.
-	 */
-	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
-	@Override
-	public int getLastStartupCheckCount() {
-		return lastStartupCheckCount;
-	}
-
-	/**
-	 * @return What was the exit code from the last time the factory subprocess
-	 *         was killed?
-	 */
-	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
-	@Override
-	public Integer getLastExitCode() {
-		return lastExitCode;
-	}
-
-	/**
-	 * @return What the factory subprocess's main RMI interface is registered
-	 *         as.
-	 */
-	@ManagedAttribute(description = "What the factory subprocess's main RMI interface is registered as.", currencyTimeLimit = 60)
-	@Override
-	public String getFactoryProcessName() {
-		return factoryProcessName;
-	}
-
-	/**
-	 * Makes the subprocess that manufactures runs.
-	 * 
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	public void initFactory() throws Exception {
-		if (factory != null)
-			return;
-		// Generate the arguments to use when spawning the subprocess
-		factoryProcessName = state.getFactoryProcessNamePrefix() + randomUUID();
-		ProcessBuilder p = new ProcessBuilder(getJavaBinary());
-		p.command().add("-jar");
-		p.command().add(getServerWorkerJar());
-		if (getExecuteWorkflowScript() == null)
-			log.fatal("no execute workflow script");
-		p.command().add(getExecuteWorkflowScript());
-		p.command().addAll(asList(getExtraArguments()));
-		p.command().add(factoryProcessName);
-		p.redirectErrorStream(true);
-		p.directory(new File(getProperty("javax.servlet.context.tempdir",
-				getProperty("java.io.tmpdir"))));
-
-		// Spawn the subprocess
-		log.info("about to create subprocess: " + p.command());
-		
-		factoryProcess = launchSubprocess(p);
-		outlog = new StreamLogger("FactoryStdout", factoryProcess.getInputStream()) {
-			@Override
-			protected void write(String msg) {
-				log.info(msg);
-			}
-		};
-		errlog = new StreamLogger("FactoryStderr", factoryProcess.getErrorStream()) {
-			@Override
-			protected void write(String msg) {
-				log.info(msg);
-			}
-		};
-
-		// Wait for the subprocess to register itself in the RMI registry
-		Calendar deadline = Calendar.getInstance();
-		deadline.add(SECOND, state.getWaitSeconds());
-		Exception lastException = null;
-		lastStartupCheckCount = 0;
-		while (deadline.after(Calendar.getInstance())) {
-			try {
-				sleep(state.getSleepMS());
-				lastStartupCheckCount++;
-				factory = getRemoteFactoryHandle(factoryProcessName);
-				initInteractionDetails(factory);
-				return;
-			} catch (InterruptedException ie) {
-				continue;
-			} catch (NotBoundException nbe) {
-				lastException = nbe;
-				log.info("resource \"" + factoryProcessName
-						+ "\" not yet registered...");
-				continue;
-			} catch (RemoteException re) {
-				// Unpack a remote exception if we can
-				lastException = re;
-				try {
-					if (re.getCause() != null)
-						lastException = (Exception) re.getCause();
-				} catch (Throwable t) {
-					// Ignore!
-				}
-			} catch (RuntimeException e) {
-				lastException = e;
-			}
-		}
-		if (lastException == null)
-			lastException = new InterruptedException();
-		throw lastException;
-	}
-
-	private StreamLogger outlog, errlog;
-
-	private void stopLoggers() {
-		if (outlog != null)
-			outlog.stop();
-		outlog = null;
-		if (errlog != null)
-			errlog.stop();
-		errlog = null;
-	}
-
-	private RemoteRunFactory getRemoteFactoryHandle(String name)
-			throws RemoteException, NotBoundException {
-		log.info("about to look up resource called " + name);
-		try {
-			// Validate registry connection first
-			getTheRegistry().list();
-		} catch (ConnectException | ConnectIOException e) {
-			log.warn("connection problems with registry", e);
-		}
-		RemoteRunFactory rrf = (RemoteRunFactory) getTheRegistry().lookup(name);
-		log.info("successfully connected to factory subprocess "
-				+ factoryProcessName);
-		return rrf;
-	}
-
-	/**
-	 * Destroys the subprocess that manufactures runs.
-	 */
-	@PreDestroy
-	public void killFactory() {
-		if (factory != null) {
-			log.info("requesting shutdown of " + factoryProcessName);
-			try {
-				factory.shutdown();
-				sleep(700);
-			} catch (RemoteException e) {
-				log.warn(factoryProcessName + " failed to shut down nicely", e);
-			} catch (InterruptedException e) {
-				if (log.isDebugEnabled())
-					log.debug("interrupted during wait after asking "
-							+ factoryProcessName + " to shut down", e);
-			} finally {
-				factory = null;
-			}
-		}
-
-		if (factoryProcess != null) {
-			int code = -1;
-			try {
-				lastExitCode = code = factoryProcess.exitValue();
-				log.info(factoryProcessName + " already dead?");
-			} catch (RuntimeException e) {
-				log.info("trying to force death of " + factoryProcessName);
-				try {
-					factoryProcess.destroy();
-					sleep(350); // takes a little time, even normally
-					lastExitCode = code = factoryProcess.exitValue();
-				} catch (Exception e2) {
-					code = -1;
-				}
-			} finally {
-				factoryProcess = null;
-				stopLoggers();
-			}
-			if (code > 128) {
-				log.info(factoryProcessName + " died with signal="
-						+ (code - 128));
-			} else if (code >= 0) {
-				log.info(factoryProcessName + " process killed: code=" + code);
-			} else {
-				log.warn(factoryProcessName + " not yet dead");
-			}
-		}
-	}
-
-	/**
-	 * The real core of the run builder, factored out from its reliability
-	 * support.
-	 * 
-	 * @param creator
-	 *            Who created this workflow?
-	 * @param wf
-	 *            The serialized workflow.
-	 * @return The remote handle of the workflow run.
-	 * @throws RemoteException
-	 *             If anything fails (communications error, etc.)
-	 */
-	private RemoteSingleRun getRealRun(@Nonnull UsernamePrincipal creator,
-			@Nonnull byte[] wf, UUID id) throws RemoteException {
-		@Nonnull
-		String globaluser = "Unknown Person";
-		if (creator != null)
-			globaluser = creator.getName();
-		RemoteSingleRun rsr = getFactory().make(wf, globaluser,
-				makeURReciver(creator), id);
-		incrementRunCount();
-		return rsr;
-	}
-
-	@Override
-	protected RemoteSingleRun getRealRun(UsernamePrincipal creator,
-			Workflow workflow, UUID id) throws Exception {
-		@Nonnull
-		byte[] wf = serializeWorkflow(workflow);
-		for (int i = 0; i < 3; i++) {
-			initFactory();
-			try {
-				return getRealRun(creator, wf, id);
-			} catch (ConnectException | ConnectIOException e) {
-				// factory was lost; try to recreate
-			}
-			killFactory();
-		}
-		throw new NoCreateException("total failure to connect to factory "
-				+ factoryProcessName + "despite attempting restart");
-	}
-
-	@Override
-	public String[] getFactoryProcessMapping() {
-		return new String[0];
-	}
-
-	@Override
-	protected int operatingCount() throws Exception {
-		return getFactory().countOperatingRuns();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java
deleted file mode 100644
index a2e5ff7..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- */
-package org.taverna.server.master.localworker;
-/*
- * 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.
- */
-
-import static java.lang.System.getProperty;
-import static java.lang.Thread.sleep;
-import static java.util.Arrays.asList;
-import static java.util.Calendar.SECOND;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.localworker.AbstractRemoteRunFactory.launchSubprocess;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.rmi.ConnectException;
-import java.rmi.ConnectIOException;
-import java.rmi.NotBoundException;
-import java.rmi.RemoteException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.core.annotation.Order;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A simple factory for workflow runs that forks runs from a subprocess.
- * 
- * @author Donal Fellows
- */
-@ManagedResource(objectName = JMX_ROOT + "RunFactory", description = "The factory for a user-specific forked run.")
-public class IdAwareForkRunFactory extends AbstractRemoteRunFactory implements
-		ConfigurableRunFactory {
-	private MetaFactory forker;
-	private Map<String, RemoteRunFactory> factory;
-	private Map<String, String> factoryProcessName;
-
-	/**
-	 * Create a factory for remote runs that works by forking off a subprocess.
-	 * 
-	 * @throws JAXBException
-	 *             Shouldn't happen.
-	 */
-	public IdAwareForkRunFactory() throws JAXBException {
-		factory = new HashMap<>();
-		factoryProcessName = new HashMap<>();
-	}
-
-	@Override
-	protected void reinitFactory() {
-		boolean makeForker = forker != null;
-		try {
-			killForker();
-		} catch (Exception e) {
-			log.warn("exception when killing secure-fork process", e);
-		}
-		try {
-			if (makeForker)
-				initMetaFactory();
-		} catch (Exception e) {
-			log.fatal("failed to make secure-fork process", e);
-		}
-	}
-
-	/**
-	 * @return How many checks were done for the worker process the last time a
-	 *         spawn was tried.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
-	public int getLastStartupCheckCount() {
-		return forker == null ? 0 : forker.lastStartupCheckCount();
-	}
-
-	/**
-	 * @return What was the exit code from the last time the factory subprocess
-	 *         was killed?
-	 */
-	@Override
-	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
-	public Integer getLastExitCode() {
-		return forker == null ? null : forker.lastExitCode();
-	}
-
-	/**
-	 * @return The mapping of user names to RMI factory IDs.
-	 */
-	@Override
-	@ManagedAttribute(description = "The mapping of user names to RMI factory IDs.", currencyTimeLimit = 60)
-	public String[] getFactoryProcessMapping() {
-		ArrayList<String> result = new ArrayList<>();
-		ArrayList<String> keys = new ArrayList<>(factoryProcessName.keySet());
-		String[] ks = keys.toArray(new String[keys.size()]);
-		Arrays.sort(ks);
-		for (String k : ks) {
-			result.add(k);
-			result.add(factoryProcessName.get(k));
-		}
-		return result.toArray(new String[result.size()]);
-	}
-
-	/**
-	 * How construction of factories is actually done.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public interface MetaFactory {
-		/**
-		 * Make a factory for the given user.
-		 * 
-		 * @param username
-		 *            Who to make it for.
-		 * @return Handle of the factory.
-		 * @throws Exception
-		 *             If anything goes wrong.
-		 */
-		RemoteRunFactory make(String username) throws Exception;
-
-		/**
-		 * Shut down the meta-factory. It is not defined whether factories
-		 * created by it are also shut down at the same time.
-		 * 
-		 * @throws IOException
-		 *             If something goes wrong when communicating with the
-		 *             meta-factory.
-		 * @throws InterruptedException
-		 *             If something stops us waiting for the shut down to
-		 *             happen.
-		 */
-		void close() throws IOException, InterruptedException;
-
-		int lastStartupCheckCount();
-
-		Integer lastExitCode();
-	}
-
-	void registerFactory(String username, String fpn, RemoteRunFactory f) {
-		factoryProcessName.put(username, fpn);
-		factory.put(username, f);
-	}
-
-	/**
-	 * Makes the connection to the meta-factory that makes factories.
-	 * 
-	 * @throws IOException
-	 *             If the connection fails.
-	 */
-	@PostConstruct
-	void initMetaFactory() throws IOException {
-		log.info("waiting for availability of default RMI registry");
-		getTheRegistry();
-		log.info("constructing secure fork subprocess");
-		forker = new SecureFork(this, state, log);
-	}
-
-	private void killForker() throws IOException, InterruptedException {
-		try {
-			if (forker != null)
-				forker.close();
-		} finally {
-			forker = null;
-		}
-	}
-
-	/**
-	 * Makes the subprocess that manufactures runs.
-	 * 
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	private void initFactory(String username) throws Exception {
-		if (factory.containsKey(username))
-			return;
-		if (forker == null)
-			initMetaFactory();
-		forker.make(username);
-	}
-
-	/**
-	 * Destroys the subprocess that manufactures runs.
-	 */
-	@PreDestroy
-	public void killFactories() {
-		if (!factory.isEmpty()) {
-			Iterator<String> keys = factory.keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				log.info("requesting shutdown of "
-						+ factoryProcessName.get(key));
-				try {
-					factory.get(key).shutdown();
-				} catch (RemoteException e) {
-					log.warn(factoryProcessName.get(key)
-							+ " failed to shut down nicely", e);
-				} finally {
-					keys.remove();
-					factoryProcessName.remove(key);
-				}
-			}
-			try {
-				sleep(700);
-			} catch (InterruptedException e) {
-				if (log.isDebugEnabled())
-					log.debug("interrupted during wait after "
-							+ "asking factories to shut down", e);
-			}
-		}
-
-		try {
-			killForker();
-		} catch (Exception e) {
-			if (log.isDebugEnabled())
-				log.debug("exception in shutdown of secure-fork process", e);
-		}
-	}
-
-	@Override
-	protected void finalize() throws Throwable {
-		killFactories();
-		super.finalize();
-	}
-
-	@Autowired
-	public void setIdMapper(LocalIdentityMapper mapper) {
-		this.mapper = mapper;
-	}
-
-	private LocalIdentityMapper mapper;
-
-	/**
-	 * The real core of the run builder, factored out from its reliability
-	 * support.
-	 * 
-	 * @param creator
-	 *            Who created this workflow?
-	 * @param username
-	 *            What user account is this workflow to be executed in?
-	 * @param wf
-	 *            The serialized workflow.
-	 * @return The remote handle of the workflow run.
-	 * @throws RemoteException
-	 *             If anything fails (communications error, etc.)
-	 */
-	private RemoteSingleRun getRealRun(@Nonnull UsernamePrincipal creator,
-			@Nonnull String username, @Nonnull byte[] wf, UUID id)
-			throws RemoteException {
-		String globaluser = "Unknown Person";
-		if (creator != null)
-			globaluser = creator.getName();
-		RemoteSingleRun rsr = factory.get(username).make(wf, globaluser,
-				makeURReciver(creator), id);
-		incrementRunCount();
-		return rsr;
-	}
-
-	@Override
-	protected RemoteSingleRun getRealRun(UsernamePrincipal creator,
-			Workflow workflow, UUID id) throws Exception {
-		byte[] wf = serializeWorkflow(workflow);
-		String username = mapper == null ? null : mapper
-				.getUsernameForPrincipal(creator);
-		if (username == null)
-			throw new Exception("cannot determine who to run workflow as; "
-					+ "local identity mapper returned null");
-		for (int i = 0; i < 3; i++) {
-			if (!factory.containsKey(username))
-				initFactory(username);
-			try {
-				return getRealRun(creator, username, wf, id);
-			} catch (ConnectException | ConnectIOException e) {
-				// factory was lost; try to recreate
-			}
-			factory.remove(username);
-		}
-		throw new NoCreateException("total failure to connect to factory "
-				+ factoryProcessName + "despite attempting restart");
-	}
-
-	@Value("${secureForkPasswordFile}")
-	@Order(20)
-	public void setPasswordSource(String passwordSource) {
-		if (passwordSource == null || passwordSource.isEmpty()
-				|| passwordSource.startsWith("${"))
-			state.setDefaultPasswordFile(null);
-		else
-			state.setDefaultPasswordFile(passwordSource);
-		if (state.getPasswordFile() == null)
-			log.info("assuming password-free forking enabled");
-		else
-			log.info("configured secureForkPasswordFile from context as "
-					+ state.getPasswordFile());
-	}
-
-	@Override
-	public String getFactoryProcessName() {
-		return "<PROPERTY-NOT-SUPPORTED>";
-	}
-
-	@Override
-	protected int operatingCount() throws Exception {
-		int total = 0;
-		for (RemoteRunFactory rrf : factory.values())
-			total += rrf.countOperatingRuns();
-		return total;
-	}
-}
-
-/**
- * The connector that handles the secure fork process itself.
- * 
- * @author Donal Fellows
- */
-class SecureFork implements IdAwareForkRunFactory.MetaFactory {
-	private IdAwareForkRunFactory main;
-	private Process process;
-	private PrintWriter channel;
-	private int lastStartupCheckCount;
-	private Integer lastExitCode;
-	private Log log;
-	private LocalWorkerState state;
-	private StreamLogger out, err;
-
-	/**
-	 * Construct the command to run the meta-factory process.
-	 * 
-	 * @param args
-	 *            The live list of arguments to pass.
-	 */
-	public void initFactoryArgs(List<String> args) {
-		args.add(main.getJavaBinary());
-		String pwf = main.getPasswordFile();
-		if (pwf != null) {
-			args.add("-Dpassword.file=" + pwf);
-		}
-		args.add("-jar");
-		args.add(main.getServerForkerJar());
-		args.add(main.getJavaBinary());
-		args.add("-jar");
-		args.add(main.getServerWorkerJar());
-		if (main.getExecuteWorkflowScript() == null)
-			log.fatal("no execute workflow script");
-		args.add(main.getExecuteWorkflowScript());
-		args.addAll(asList(main.getExtraArguments()));
-	}
-
-	SecureFork(IdAwareForkRunFactory main, LocalWorkerState state, Log log)
-			throws IOException {
-		this.main = main;
-		this.log = log;
-		this.state = state;
-		ProcessBuilder p = new ProcessBuilder();
-		initFactoryArgs(p.command());
-		p.redirectErrorStream(true);
-		p.directory(new File(getProperty("javax.servlet.context.tempdir",
-				getProperty("java.io.tmpdir"))));
-
-		// Spawn the subprocess
-		log.info("about to create subprocess: " + p.command());
-		log.info("subprocess directory: " + p.directory());
-		process = launchSubprocess(p);
-		channel = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
-				process.getOutputStream())), true);
-		// Log the responses
-		out = new StreamLogger("ForkedStdout", process.getInputStream()) {
-			@Override
-			protected void write(String msg) {
-				log.info(msg);
-			}
-		};
-		err = new StreamLogger("ForkedStderr", process.getErrorStream()) {
-			@Override
-			protected void write(String msg) {
-				log.info(msg);
-			}
-		};
-	}
-
-	@Override
-	public void close() throws IOException, InterruptedException {
-		try {
-			if (process != null) {
-				log.info("about to close down subprocess");
-				channel.close();
-				int code = -1;
-				try {
-					try {
-						code = process.exitValue();
-						log.info("secure-fork process already dead?");
-					} catch (IllegalThreadStateException e) {
-						try {
-							code = process.waitFor();
-						} catch (InterruptedException e1) {
-							log.info("interrupted waiting for natural death of secure-fork process?!");
-							process.destroy();
-							code = process.waitFor();
-						}
-					}
-				} finally {
-					lastExitCode = code;
-					if (code > 128) {
-						log.info("secure-fork process died with signal="
-								+ (code - 128));
-					} else if (code >= 0) {
-						log.info("secure-fork process killed: code=" + code);
-					} else {
-						log.warn("secure-fork process not yet dead");
-					}
-				}
-			}
-		} finally {
-			process = null;
-			channel = null;
-			out.stop();
-			err.stop();
-		}
-	}
-
-	protected void make(String username, String fpn) {
-		log.info("about to request subprocess creation for " + username
-				+ " producing ID " + fpn);
-		channel.println(username + " " + fpn);
-	}
-
-	@Override
-	public RemoteRunFactory make(String username) throws Exception {
-		try {
-			main.getTheRegistry().list(); // Validate registry connection first
-		} catch (ConnectException | ConnectIOException e) {
-			log.warn("connection problems with registry", e);
-		} catch (RemoteException e) {
-			if (e.getCause() != null && e.getCause() instanceof Exception) {
-				throw (Exception) e.getCause();
-			}
-			log.warn("connection problems with registry", e);
-		}
-
-		String fpn = state.getFactoryProcessNamePrefix() + randomUUID();
-		make(username, fpn);
-
-		// Wait for the subprocess to register itself in the RMI registry
-		Calendar deadline = Calendar.getInstance();
-		deadline.add(SECOND, state.getWaitSeconds());
-		Exception lastException = null;
-		lastStartupCheckCount = 0;
-		while (deadline.after(Calendar.getInstance())) {
-			try {
-				sleep(state.getSleepMS());
-				lastStartupCheckCount++;
-				log.info("about to look up resource called " + fpn);
-				RemoteRunFactory f = (RemoteRunFactory) main.getTheRegistry()
-						.lookup(fpn);
-				log.info("successfully connected to factory subprocess " + fpn);
-				main.initInteractionDetails(f);
-				main.registerFactory(username, fpn, f);
-				return f;
-			} catch (InterruptedException ie) {
-				continue;
-			} catch (NotBoundException nbe) {
-				lastException = nbe;
-				log.info("resource \"" + fpn + "\" not yet registered...");
-				continue;
-			} catch (RemoteException re) {
-				// Unpack a remote exception if we can
-				lastException = re;
-				try {
-					if (re.getCause() != null)
-						lastException = (Exception) re.getCause();
-				} catch (Throwable t) {
-					// Ignore!
-				}
-			} catch (Exception e) {
-				lastException = e;
-			}
-		}
-		if (lastException == null)
-			lastException = new InterruptedException();
-		throw lastException;
-	}
-
-	@Override
-	public Integer lastExitCode() {
-		return lastExitCode;
-	}
-
-	@Override
-	public int lastStartupCheckCount() {
-		return lastStartupCheckCount;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java
deleted file mode 100644
index 803c201..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- */
-package org.taverna.server.master.localworker;
-/*
- * 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.
- */
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * Provider of the configuration of the "localworker.factory" bean, which is
- * sufficiently complex to be too hard to manufacture directly from the XML
- * configuration.
- * 
- * @author Donal Fellows
- */
-@Configuration
-public class LocalWorkerFactory {
-	@Bean(name = "localworker.factory")
-	AbstractRemoteRunFactory getLocalworkerFactory(
-			@Value("${backEndFactory}") String mode) throws Exception {
-		if (mode == null || mode.isEmpty() || mode.startsWith("${"))
-			throw new Exception("no value for ${backEndFactory}");
-		Class<?> c = Class.forName(mode);
-		if (AbstractRemoteRunFactory.class.isAssignableFrom(c))
-			return (AbstractRemoteRunFactory) c.newInstance();
-		throw new Exception("unknown remote run factory: " + mode);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java
deleted file mode 100644
index e32dcca..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- */
-package org.taverna.server.master.localworker;
-/*
- * 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.
- */
-
-import static java.io.File.separator;
-import static java.lang.System.getProperty;
-import static java.rmi.registry.Registry.REGISTRY_PORT;
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.unmodifiableList;
-import static org.taverna.server.master.defaults.Default.EXTRA_ARGUMENTS;
-import static org.taverna.server.master.defaults.Default.PASSWORD_FILE;
-import static org.taverna.server.master.defaults.Default.REGISTRY_JAR;
-import static org.taverna.server.master.defaults.Default.RMI_PREFIX;
-import static org.taverna.server.master.defaults.Default.RUN_LIFE_MINUTES;
-import static org.taverna.server.master.defaults.Default.RUN_OPERATING_LIMIT;
-import static org.taverna.server.master.defaults.Default.SECURE_FORK_IMPLEMENTATION_JAR;
-import static org.taverna.server.master.defaults.Default.SERVER_WORKER_IMPLEMENTATION_JAR;
-import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_POLL_SLEEP;
-import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_WAIT;
-import static org.taverna.server.master.localworker.PersistedState.KEY;
-import static org.taverna.server.master.localworker.PersistedState.makeInstance;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.net.URI;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.jdo.annotations.PersistenceAware;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.defaults.Default;
-import org.taverna.server.master.utils.JDOSupport;
-import org.taverna.server.master.worker.WorkerModel;
-
-/**
- * The persistent state of a local worker factory.
- * 
- * @author Donal Fellows
- */
-@PersistenceAware
-public class LocalWorkerState extends JDOSupport<PersistedState> implements
-		WorkerModel {	
-	public LocalWorkerState() {
-		super(PersistedState.class);
-	}
-
-	private LocalWorkerState self;
-
-	@Required
-	public void setSelf(LocalWorkerState self) {
-		this.self = self;
-	}
-
-	/** Initial lifetime of runs, in minutes. */
-	int defaultLifetime;
-	/**
-	 * Maximum number of runs to exist at once. Note that this includes when
-	 * they are just existing for the purposes of file transfer (
-	 * {@link Status#Initialized}/{@link Status#Finished} states).
-	 */
-	int maxRuns;
-	/**
-	 * Prefix to use for RMI names.
-	 */
-	String factoryProcessNamePrefix;
-	/**
-	 * Full path name of the script used to start running a workflow; normally
-	 * expected to be "<i>somewhere/</i><tt>executeWorkflow.sh</tt>".
-	 */
-	String executeWorkflowScript;
-	/** Default value for {@link #executeWorkflowScript}. */
-	private transient String defaultExecuteWorkflowScript;
-	/**
-	 * Full path name of the file containing the password used to launch workers
-	 * as other users. The file is normally expected to contain a single line,
-	 * the password, and to be thoroughly locked down so only the user running
-	 * the server (e.g., "<tt>tomcat</tt>") can read it; it will probably reside
-	 * in either the user's home directory or in a system configuration
-	 * directory.
-	 */
-	String passwordFile;
-	/** Default value for {@link #passwordFile}. */
-	private transient String defaultPasswordFile = PASSWORD_FILE;
-	/**
-	 * The extra arguments to pass to the subprocess.
-	 */
-	String[] extraArgs;
-	/**
-	 * How long to wait for subprocess startup, in seconds.
-	 */
-	int waitSeconds;
-	/**
-	 * Polling interval to use during startup, in milliseconds.
-	 */
-	int sleepMS;
-	/**
-	 * Full path name to the worker process's implementation JAR.
-	 */
-	String serverWorkerJar;
-	private static final String DEFAULT_WORKER_JAR = LocalWorkerState.class
-			.getClassLoader().getResource(SERVER_WORKER_IMPLEMENTATION_JAR)
-			.getFile();
-	/**
-	 * Full path name to the Java binary to use to run the subprocess.
-	 */
-	String javaBinary;
-	private static final String DEFAULT_JAVA_BINARY = getProperty("java.home")
-			+ separator + "bin" + separator + "java";
-	/**
-	 * Full path name to the secure fork process's implementation JAR.
-	 */
-	String serverForkerJar;
-	private static final String DEFAULT_FORKER_JAR = LocalWorkerState.class
-			.getClassLoader().getResource(SECURE_FORK_IMPLEMENTATION_JAR)
-			.getFile();
-
-	String registryHost;
-	int registryPort;
-
-	int operatingLimit;
-
-	URI[] permittedWorkflows;
-	private String registryJar;
-	private static final String DEFAULT_REGISTRY_JAR = LocalWorkerState.class
-			.getClassLoader().getResource(REGISTRY_JAR).getFile();
-
-	@Override
-	public void setDefaultLifetime(int defaultLifetime) {
-		this.defaultLifetime = defaultLifetime;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getDefaultLifetime() {
-		return defaultLifetime < 1 ? RUN_LIFE_MINUTES : defaultLifetime;
-	}
-
-	@Override
-	public void setMaxRuns(int maxRuns) {
-		this.maxRuns = maxRuns;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getMaxRuns() {
-		return maxRuns < 1 ? Default.RUN_COUNT_MAX : maxRuns;
-	}
-
-	@Override
-	public int getOperatingLimit() {
-		return operatingLimit < 1 ? RUN_OPERATING_LIMIT : operatingLimit;
-	}
-
-	@Override
-	public void setOperatingLimit(int operatingLimit) {
-		this.operatingLimit = operatingLimit;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public void setFactoryProcessNamePrefix(String factoryProcessNamePrefix) {
-		this.factoryProcessNamePrefix = factoryProcessNamePrefix;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getFactoryProcessNamePrefix() {
-		return factoryProcessNamePrefix == null ? RMI_PREFIX
-				: factoryProcessNamePrefix;
-	}
-
-	@Override
-	public void setExecuteWorkflowScript(String executeWorkflowScript) {
-		this.executeWorkflowScript = executeWorkflowScript;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getExecuteWorkflowScript() {
-		return executeWorkflowScript == null ? defaultExecuteWorkflowScript
-				: executeWorkflowScript;
-	}
-
-	private static String guessWorkflowScript() {
-		File utilDir = new File(DEFAULT_WORKER_JAR).getParentFile();
-		File[] dirs = utilDir.listFiles(new FilenameFilter() {
-			@Override
-			public boolean accept(File dir, String name) {
-				// Support both taverna-commandline* (2.5) and
-				// taverna-command-line* (3.1)
-				return name.toLowerCase().startsWith("taverna-command");
-			}
-		});
-		if (dirs.length == 0) { 
-			throw new IllegalStateException("Can't find taverna-command* distro in " + utilDir);
-		}
-		File script = new File(dirs[0], "executeworkflow.sh");
-		if (! script.isFile()) {
-			throw new IllegalStateException("Can't find launcher script " + script);
-		}
-		return script.toString();
-	}
-
-	/**
-	 * Set what executeworkflow script to use by default. This is the value that
-	 * is used if not overridden by the administration interface.
-	 * 
-	 * @param defaultScript
-	 *            Full path to the script to use.
-	 */
-	public void setDefaultExecuteWorkflowScript(String defaultScript) {
-		if (defaultScript.startsWith("${") || defaultScript.equals("NONE")) {
-			this.defaultExecuteWorkflowScript = guessWorkflowScript();
-			return;
-		}
-		this.defaultExecuteWorkflowScript = defaultScript;
-	}
-
-	String getDefaultExecuteWorkflowScript() {
-		return defaultExecuteWorkflowScript;
-	}
-
-	@Override
-	public void setExtraArgs(String[] extraArgs) {
-		this.extraArgs = extraArgs.clone();
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String[] getExtraArgs() {
-		return extraArgs == null ? EXTRA_ARGUMENTS : extraArgs.clone();
-	}
-
-	@Override
-	public void setWaitSeconds(int waitSeconds) {
-		this.waitSeconds = waitSeconds;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getWaitSeconds() {
-		return waitSeconds < 1 ? SUBPROCESS_START_WAIT : waitSeconds;
-	}
-
-	@Override
-	public void setSleepMS(int sleepMS) {
-		this.sleepMS = sleepMS;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getSleepMS() {
-		return sleepMS < 1 ? SUBPROCESS_START_POLL_SLEEP : sleepMS;
-	}
-
-	@Override
-	public void setServerWorkerJar(String serverWorkerJar) {
-		this.serverWorkerJar = serverWorkerJar;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getServerWorkerJar() {
-		return serverWorkerJar == null ? DEFAULT_WORKER_JAR : serverWorkerJar;
-	}
-
-	@Override
-	public void setServerForkerJar(String serverForkerJar) {
-		this.serverForkerJar = serverForkerJar;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getServerForkerJar() {
-		return serverForkerJar == null ? DEFAULT_FORKER_JAR : serverForkerJar;
-	}
-
-	@Override
-	public void setJavaBinary(String javaBinary) {
-		this.javaBinary = javaBinary;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getJavaBinary() {
-		return javaBinary == null ? DEFAULT_JAVA_BINARY : javaBinary;
-	}
-
-	@Override
-	public void setPasswordFile(String passwordFile) {
-		this.passwordFile = passwordFile;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getPasswordFile() {
-		return passwordFile == null ? defaultPasswordFile : passwordFile;
-	}
-
-	void setDefaultPasswordFile(String defaultPasswordFile) {
-		this.defaultPasswordFile = defaultPasswordFile;
-	}
-
-	@Override
-	public void setRegistryHost(String registryHost) {
-		this.registryHost = (registryHost == null ? "" : registryHost);
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getRegistryHost() {
-		return (registryHost == null || registryHost.isEmpty()) ? null
-				: registryHost;
-	}
-
-	@Override
-	public void setRegistryPort(int registryPort) {
-		this.registryPort = ((registryPort < 1 || registryPort > 65534) ? REGISTRY_PORT
-				: registryPort);
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getRegistryPort() {
-		return registryPort == 0 ? REGISTRY_PORT : registryPort;
-	}
-
-	@Override
-	public String getRegistryJar() {
-		return registryJar == null ? DEFAULT_REGISTRY_JAR : registryJar;
-	}
-
-	@Override
-	public void setRegistryJar(String rmiRegistryJar) {
-		this.registryJar = (rmiRegistryJar == null || rmiRegistryJar.isEmpty()) ? null
-				: rmiRegistryJar;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public List<URI> getPermittedWorkflowURIs() {
-		if (permittedWorkflows == null || permittedWorkflows.length == 0)
-			return emptyList();
-		return unmodifiableList(asList(permittedWorkflows));
-	}
-
-	@Override
-	public void setPermittedWorkflowURIs(List<URI> permittedWorkflows) {
-		if (permittedWorkflows == null || permittedWorkflows.isEmpty())
-			this.permittedWorkflows = new URI[0];
-		else
-			this.permittedWorkflows = permittedWorkflows
-					.toArray(new URI[permittedWorkflows.size()]);
-		if (loadedState)
-			self.store();
-	}
-
-	public static final boolean DEFAULT_GENERATE_PROVENANCE = false;
-	private Boolean generateProvenance;
-
-	@Override
-	public boolean getGenerateProvenance() {
-		Boolean g = generateProvenance;
-		return g == null ? DEFAULT_GENERATE_PROVENANCE : (boolean) g;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean generate) {
-		this.generateProvenance = generate;
-		if (loadedState)
-			self.store();
-	}
-
-	// --------------------------------------------------------------
-
-	private boolean loadedState;
-
-	@PostConstruct
-	@WithinSingleTransaction
-	public void load() {
-		if (loadedState || !isPersistent())
-			return;
-		WorkerModel state = getById(KEY);
-		if (state == null) {
-			store();
-			return;
-		}
-
-		defaultLifetime = state.getDefaultLifetime();
-		executeWorkflowScript = state.getExecuteWorkflowScript();
-		extraArgs = state.getExtraArgs();
-		factoryProcessNamePrefix = state.getFactoryProcessNamePrefix();
-		javaBinary = state.getJavaBinary();
-		maxRuns = state.getMaxRuns();
-		serverWorkerJar = state.getServerWorkerJar();
-		serverForkerJar = state.getServerForkerJar();
-		passwordFile = state.getPasswordFile();
-		sleepMS = state.getSleepMS();
-		waitSeconds = state.getWaitSeconds();
-		registryHost = state.getRegistryHost();
-		registryPort = state.getRegistryPort();
-		operatingLimit = state.getOperatingLimit();
-		List<URI> pwu = state.getPermittedWorkflowURIs();
-		permittedWorkflows = (URI[]) pwu.toArray(new URI[pwu.size()]);
-		registryJar = state.getRegistryJar();
-		generateProvenance = state.getGenerateProvenance();
-
-		loadedState = true;
-	}
-
-	@WithinSingleTransaction
-	public void store() {
-		if (!isPersistent())
-			return;
-		WorkerModel state = getById(KEY);
-		if (state == null)
-			state = persist(makeInstance());
-
-		state.setDefaultLifetime(defaultLifetime);
-		state.setExecuteWorkflowScript(executeWorkflowScript);
-		state.setExtraArgs(extraArgs);
-		state.setFactoryProcessNamePrefix(factoryProcessNamePrefix);
-		state.setJavaBinary(javaBinary);
-		state.setMaxRuns(maxRuns);
-		state.setServerWorkerJar(serverWorkerJar);
-		state.setServerForkerJar(serverForkerJar);
-		state.setPasswordFile(passwordFile);
-		state.setSleepMS(sleepMS);
-		state.setWaitSeconds(waitSeconds);
-		state.setRegistryHost(registryHost);
-		state.setRegistryPort(registryPort);
-		state.setOperatingLimit(operatingLimit);
-		if (permittedWorkflows != null)
-			state.setPermittedWorkflowURIs(asList(permittedWorkflows));
-		state.setRegistryJar(registryJar);
-		if (generateProvenance != null)
-			state.setGenerateProvenance(generateProvenance);
-
-		loadedState = true;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java
deleted file mode 100644
index 3ed4c51..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- */
-package org.taverna.server.master.localworker;
-/*
- * 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.
- */
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jdo.annotations.Join;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.PrimaryKey;
-
-import org.taverna.server.master.worker.WorkerModel;
-
-/**
- * The actual database connector for persisted local worker state.
- * 
- * @author Donal Fellows
- */
-/*
- * WARNING! If you change the name of this class, update persistence.xml as
- * well!
- */
-@PersistenceCapable(table = PersistedState.TABLE)
-class PersistedState implements WorkerModel {
-	static final String TABLE = "LOCALWORKERSTATE__PERSISTEDSTATE";
-
-	static PersistedState makeInstance() {
-		PersistedState o = new PersistedState();
-		o.ID = KEY;
-		return o;
-	}
-
-	@PrimaryKey(column = "ID")
-	protected int ID;
-
-	static final int KEY = 32;
-
-	@Persistent
-	private int defaultLifetime;
-	@Persistent
-	private int maxRuns;
-	@Persistent
-	private String factoryProcessNamePrefix;
-	@Persistent
-	private String executeWorkflowScript;
-	@Persistent(serialized = "true")
-	private String[] extraArgs;
-	@Persistent
-	private int waitSeconds;
-	@Persistent
-	private int sleepMS;
-	@Persistent
-	private String serverWorkerJar;
-	@Persistent
-	private String serverForkerJar;
-	@Persistent
-	private String registryJar;
-	@Persistent
-	private String passwordFile;
-	@Persistent
-	private String javaBinary;
-	@Persistent
-	private int registryPort;
-	@Persistent
-	private String registryHost;
-	@Persistent
-	private int operatingLimit;
-	@Persistent(defaultFetchGroup = "true")
-	@Join(table = TABLE + "_PERMWFURI", column = "ID")
-	private String[] permittedWorkflows;
-	@Persistent
-	private int generateProvenance;
-
-	@Override
-	public void setDefaultLifetime(int defaultLifetime) {
-		this.defaultLifetime = defaultLifetime;
-	}
-
-	@Override
-	public int getDefaultLifetime() {
-		return defaultLifetime;
-	}
-
-	@Override
-	public void setMaxRuns(int maxRuns) {
-		this.maxRuns = maxRuns;
-	}
-
-	@Override
-	public int getMaxRuns() {
-		return maxRuns;
-	}
-
-	@Override
-	public void setFactoryProcessNamePrefix(String factoryProcessNamePrefix) {
-		this.factoryProcessNamePrefix = factoryProcessNamePrefix;
-	}
-
-	@Override
-	public String getFactoryProcessNamePrefix() {
-		return factoryProcessNamePrefix;
-	}
-
-	@Override
-	public void setExecuteWorkflowScript(String executeWorkflowScript) {
-		this.executeWorkflowScript = executeWorkflowScript;
-	}
-
-	@Override
-	public String getExecuteWorkflowScript() {
-		return executeWorkflowScript;
-	}
-
-	@Override
-	public void setExtraArgs(String[] extraArgs) {
-		this.extraArgs = extraArgs;
-	}
-
-	@Override
-	public String[] getExtraArgs() {
-		return extraArgs;
-	}
-
-	@Override
-	public void setWaitSeconds(int waitSeconds) {
-		this.waitSeconds = waitSeconds;
-	}
-
-	@Override
-	public int getWaitSeconds() {
-		return waitSeconds;
-	}
-
-	@Override
-	public void setSleepMS(int sleepMS) {
-		this.sleepMS = sleepMS;
-	}
-
-	@Override
-	public int getSleepMS() {
-		return sleepMS;
-	}
-
-	@Override
-	public void setServerWorkerJar(String serverWorkerJar) {
-		this.serverWorkerJar = serverWorkerJar;
-	}
-
-	@Override
-	public String getServerWorkerJar() {
-		return serverWorkerJar;
-	}
-
-	@Override
-	public void setJavaBinary(String javaBinary) {
-		this.javaBinary = javaBinary;
-	}
-
-	@Override
-	public String getJavaBinary() {
-		return javaBinary;
-	}
-
-	@Override
-	public void setRegistryPort(int registryPort) {
-		this.registryPort = registryPort;
-	}
-
-	@Override
-	public int getRegistryPort() {
-		return registryPort;
-	}
-
-	@Override
-	public void setRegistryHost(String registryHost) {
-		this.registryHost = registryHost;
-	}
-
-	@Override
-	public String getRegistryHost() {
-		return registryHost;
-	}
-
-	@Override
-	public void setServerForkerJar(String serverForkerJar) {
-		this.serverForkerJar = serverForkerJar;
-	}
-
-	@Override
-	public String getServerForkerJar() {
-		return serverForkerJar;
-	}
-
-	@Override
-	public void setPasswordFile(String passwordFile) {
-		this.passwordFile = passwordFile;
-	}
-
-	@Override
-	public String getPasswordFile() {
-		return passwordFile;
-	}
-
-	@Override
-	public void setOperatingLimit(int operatingLimit) {
-		this.operatingLimit = operatingLimit;
-	}
-
-	@Override
-	public int getOperatingLimit() {
-		return operatingLimit;
-	}
-
-	@Override
-	public List<URI> getPermittedWorkflowURIs() {
-		String[] pw = this.permittedWorkflows;
-		if (pw == null)
-			return new ArrayList<>();
-		List<URI> uris = new ArrayList<>(pw.length);
-		for (String uri : pw)
-			uris.add(URI.create(uri));
-		return uris;
-	}
-
-	@Override
-	public void setPermittedWorkflowURIs(List<URI> permittedWorkflows) {
-		String[] pw = new String[permittedWorkflows.size()];
-		for (int i = 0; i < pw.length; i++)
-			pw[i] = permittedWorkflows.get(i).toString();
-		this.permittedWorkflows = pw;
-	}
-
-	@Override
-	public String getRegistryJar() {
-		return registryJar;
-	}
-
-	@Override
-	public void setRegistryJar(String registryJar) {
-		this.registryJar = registryJar;
-	}
-
-	@Override
-	public boolean getGenerateProvenance() {
-		return generateProvenance > 0;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean generateProvenance) {
-		this.generateProvenance = (generateProvenance ? 1 : 0);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java
deleted file mode 100644
index e563965..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.taverna.server.master.localworker;
-/*
- * 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.
- */
-
-import static java.lang.Thread.interrupted;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-
-import org.apache.commons.logging.Log;
-
-abstract class StreamLogger {
-	protected final Log log;
-	private Thread t;
-	private InputStream in;
-
-	protected StreamLogger(final String name, InputStream is) {
-		log = getLog("Taverna.Server.LocalWorker." + name);
-		in = is;
-		t = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				try (BufferedReader br = new BufferedReader(
-						new InputStreamReader(in))) {
-					String line;
-					while (!interrupted() && (line = br.readLine()) != null)
-						if (!line.isEmpty())
-							write(line);
-				} catch (IOException e) {
-					// Do nothing...
-				} catch (Exception e) {
-					log.warn("failure in reading from " + name, e);
-				}
-			}
-		}, name + ".StreamLogger");
-		t.setContextClassLoader(null);
-		t.setDaemon(true);
-		t.start();
-	}
-
-	/**
-	 * Write a line read from the subprocess to the log.
-	 * <p>
-	 * This needs to be implemented by subclasses in order for the log to be
-	 * correctly written with the class name.
-	 * 
-	 * @param msg
-	 *            The message to write. Guaranteed to have no newline characters
-	 *            in it and to be non-empty.
-	 */
-	protected abstract void write(String msg);
-
-	public void stop() {
-		log.info("trying to close down " + t.getName());
-		t.interrupt();
-		try {
-			in.close();
-		} catch (IOException e) {
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java
deleted file mode 100644
index 031ce34..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-/**
- * Implementation of a Taverna Server back-end that works by forking off
- * workflow executors on the local system.
- */
-package org.taverna.server.master.localworker;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java
deleted file mode 100644
index 2a51496..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- */
-package org.taverna.server.master.notification;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
-
-import javax.annotation.PostConstruct;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.mail.MailSender;
-import org.springframework.mail.SimpleMailMessage;
-import org.springframework.mail.javamail.JavaMailSender;
-
-/**
- * How to send a plain text message by email to someone.
- * 
- * @author Donal Fellows
- */
-public class EmailDispatcher extends RateLimitedDispatcher {
-	@Override
-	public String getName() {
-		return "mailto";
-	}
-
-	/**
-	 * @param from
-	 *            Email address that the notification is to come from.
-	 */
-	@Required
-	public void setFrom(String from) {
-		this.from = valid(from, "");
-	}
-
-	/**
-	 * @param host
-	 *            The outgoing SMTP server address.
-	 */
-	@Required
-	public void setSmtpHost(String host) {
-		this.host = valid(host, "");
-	}
-
-	/**
-	 * @param contentType
-	 *            The content type of the message to be sent. For example, "
-	 *            <tt>text/plain</tt>".
-	 */
-	public void setMessageContentType(String contentType) {
-		this.contentType = contentType;
-	}
-
-	/**
-	 * @param sender
-	 *            the sender to set
-	 */
-	public void setSender(MailSender sender) {
-		this.sender = sender;
-	}
-
-	private String from;
-	private String host;
-	private MailSender sender;
-	@SuppressWarnings("unused")
-	private String contentType = TEXT_PLAIN;
-
-	/**
-	 * Try to perform the lookup of the email service. This is called during
-	 * configuration so that any failure happens at a useful, predictable time.
-	 */
-	@PostConstruct
-	public void tryLookup() {
-		if (!isAvailable()) {
-			log.warn("no mail support; disabling email dispatch");
-			sender = null;
-			return;
-		}
-		try {
-			if (sender instanceof JavaMailSender)
-				((JavaMailSender) sender).createMimeMessage();
-		} catch (Throwable t) {
-			log.warn("sender having problems constructing messages; "
-					+ "disabling...", t);
-			sender = null;
-		}
-	}
-
-	@Override
-	public void dispatch(String messageSubject, String messageContent, String to)
-			throws Exception {
-		// Simple checks for acceptability
-		if (!to.matches(".+@.+")) {
-			log.info("did not send email notification: improper email address \""
-					+ to + "\"");
-			return;
-		}
-
-		SimpleMailMessage message = new SimpleMailMessage();
-		message.setFrom(from);
-		message.setTo(to.trim());
-		message.setSubject(messageSubject);
-		message.setText(messageContent);
-		sender.send(message);
-	}
-
-	@Override
-	public boolean isAvailable() {
-		return (host != null && !host.isEmpty() && sender != null
-				&& from != null && !from.isEmpty());
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java
deleted file mode 100644
index 711f4e6..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- */
-
-package org.taverna.server.master.notification;
-/*
- * 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.
- */
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jivesoftware.smack.Chat;
-import org.jivesoftware.smack.ConnectionConfiguration;
-import org.jivesoftware.smack.MessageListener;
-import org.jivesoftware.smack.XMPPConnection;
-import org.jivesoftware.smack.packet.Message;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * Send notifications by Jabber/XMPP.
- * 
- * @author Donal Fellows
- */
-public class JabberDispatcher implements MessageDispatcher {
-	@Override
-	public String getName() {
-		return "xmpp";
-	}
-
-	private Log log = LogFactory.getLog("Taverna.Server.Notification");
-	private XMPPConnection conn;
-	private String resource = "TavernaServer";
-	private String host = "";
-	private String user = "";
-	private String pass = "";
-
-	/**
-	 * @param resource
-	 *            The XMPP resource to use when connecting the server. This
-	 *            defaults to "<tt>TavernaServer</tt>".
-	 */
-	public void setResource(String resource) {
-		this.resource = resource;
-	}
-
-	/**
-	 * @param service
-	 *            The XMPP service URL.
-	 */
-	public void setHost(String service) {
-		if (service == null || service.trim().isEmpty()
-				|| service.trim().startsWith("$"))
-			this.host = "";
-		else
-			this.host = service.trim();
-	}
-
-	/**
-	 * @param user
-	 *            The user identity to use with the XMPP service.
-	 */
-	public void setUsername(String user) {
-		if (user == null || user.trim().isEmpty()
-				|| user.trim().startsWith("$"))
-			this.user = "";
-		else
-			this.user = user.trim();
-	}
-
-	/**
-	 * @param pass
-	 *            The password to use with the XMPP service.
-	 */
-	public void setPassword(String pass) {
-		if (pass == null || pass.trim().isEmpty()
-				|| pass.trim().startsWith("$"))
-			this.pass = "";
-		else
-			this.pass = pass.trim();
-	}
-
-	@PostConstruct
-	void setup() {
-		try {
-			if (host.isEmpty() || user.isEmpty() || pass.isEmpty()) {
-				log.info("disabling XMPP support; incomplete configuration");
-				conn = null;
-				return;
-			}
-			ConnectionConfiguration cfg = new ConnectionConfiguration(host);
-			cfg.setSendPresence(false);
-			XMPPConnection c = new XMPPConnection(cfg);
-			c.connect();
-			c.login(user, pass, resource);
-			conn = c;
-			log.info("connected to XMPP service <" + host + "> as user <"
-					+ user + ">");
-		} catch (Exception e) {
-			log.info("failed to connect to XMPP server", e);
-		}
-	}
-
-	@PreDestroy
-	public void close() {
-		if (conn != null)
-			conn.disconnect();
-		conn = null;
-	}
-
-	@Override
-	public boolean isAvailable() {
-		return conn != null;
-	}
-
-	@Override
-	public void dispatch(TavernaRun ignored, String messageSubject,
-			String messageContent, String targetParameter) throws Exception {
-		Chat chat = conn.getChatManager().createChat(targetParameter,
-				new DroppingListener());
-		Message m = new Message();
-		m.addBody(null, messageContent);
-		m.setSubject(messageSubject);
-		chat.sendMessage(m);
-	}
-
-	static class DroppingListener implements MessageListener {
-		private Log log = LogFactory
-				.getLog("Taverna.Server.Notification.Jabber");
-
-		@Override
-		public void processMessage(Chat chat, Message message) {
-			if (log.isDebugEnabled())
-				log.debug("unexpectedly received XMPP message from <"
-						+ message.getFrom() + ">; ignoring");
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java
deleted file mode 100644
index 067d154..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- */
-package org.taverna.server.master.notification;
-/*
- * 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.
- */
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * A common object for handling dispatch of event-driven messages.
- * 
- * @author Donal Fellows
- */
-public class NotificationEngine {
-	private Log log = LogFactory.getLog("Taverna.Server.Notification");
-	private Map<String, MessageDispatcher> dispatchers;
-	private List<MessageDispatcher> universalDispatchers;
-
-	/**
-	 * @param dispatchers
-	 *            The various dispatchers we want to install.
-	 */
-	@Required
-	public void setDispatchers(List<MessageDispatcher> dispatchers) {
-		this.dispatchers = new HashMap<>();
-		for (MessageDispatcher d : dispatchers)
-			this.dispatchers.put(d.getName(), d);
-	}
-
-	/**
-	 * @param dispatcherList
-	 *            A list of dispatch objects to always dispatch to.
-	 */
-	@Required
-	public void setUniversalDispatchers(List<MessageDispatcher> dispatcherList) {
-		this.universalDispatchers = dispatcherList;
-	}
-
-	private void dispatchToChosenTarget(TavernaRun originator, String scheme,
-			String target, Message message) throws Exception {
-		try {
-			MessageDispatcher d = dispatchers.get(scheme);
-			if (d != null && d.isAvailable())
-				d.dispatch(originator, message.getTitle(scheme),
-						message.getContent(scheme), target);
-			else
-				log.warn("no such notification dispatcher for " + scheme);
-		} catch (URISyntaxException e) {
-			// See if *someone* will handle the message
-			Exception e2 = null;
-			for (MessageDispatcher d : dispatchers.values())
-				try {
-					if (d.isAvailable()) {
-						d.dispatch(originator, message.getTitle(d.getName()),
-								message.getContent(d.getName()), scheme + ":"
-										+ target);
-						return;
-					}
-				} catch (Exception ex) {
-					if (log.isDebugEnabled())
-						log.debug("failed in pseudo-directed dispatch of "
-								+ scheme + ":" + target, ex);
-					e2 = ex;
-				}
-			if (e2 != null)
-				throw e2;
-		}
-	}
-
-	private void dispatchUniversally(TavernaRun originator, Message message)
-			throws Exception {
-		for (MessageDispatcher d : universalDispatchers)
-			try {
-				if (d.isAvailable())
-					d.dispatch(originator, message.getTitle(d.getName()),
-							message.getContent(d.getName()), null);
-			} catch (Exception e) {
-				log.warn("problem in universal dispatcher", e);
-			}
-	}
-
-	/**
-	 * Dispatch a message over the notification fabric.
-	 * 
-	 * @param originator
-	 *            What workflow run was the source of this message?
-	 * @param destination
-	 *            Where the message should get delivered to. The correct format
-	 *            of this is either as a URI of some form (where the scheme
-	 *            determines the dispatcher) or as an invalid URI in which case
-	 *            it is just tried against the possibilities to see if any
-	 *            succeeds.
-	 * @param subject
-	 *            The subject line of the message.
-	 * @param message
-	 *            The plain text body of the message.
-	 * @throws Exception
-	 *             If anything goes wrong with the dispatch process.
-	 */
-	public void dispatchMessage(TavernaRun originator, String destination,
-			Message message) throws Exception {
-		if (destination != null && !destination.trim().isEmpty()) {
-			try {
-				URI toURI = new URI(destination.trim());
-				dispatchToChosenTarget(originator, toURI.getScheme(),
-						toURI.getSchemeSpecificPart(), message);
-			} catch (URISyntaxException e) {
-				// Ignore
-			}
-		}
-		dispatchUniversally(originator, message);
-	}
-
-	/**
-	 * @return The message dispatchers that are actually available (i.e., not
-	 *         disabled by configuration somewhere).
-	 */
-	public List<String> listAvailableDispatchers() {
-		ArrayList<String> result = new ArrayList<>();
-		for (Map.Entry<String, MessageDispatcher> entry : dispatchers
-				.entrySet()) {
-			if (entry.getValue().isAvailable())
-				result.add(entry.getKey());
-		}
-		return result;
-	}
-
-	public interface Message {
-		String getContent(String type);
-
-		String getTitle(String type);
-	}
-}


[35/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/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
deleted file mode 100644
index de15cfa..0000000
--- a/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/Registry.java
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/Registry.java b/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/Registry.java
new file mode 100644
index 0000000..333153f
--- /dev/null
+++ b/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/Registry.java
@@ -0,0 +1,88 @@
+package org.taverna.server.rmidaemon;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/package-info.java b/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/package-info.java
new file mode 100644
index 0000000..520b928
--- /dev/null
+++ b/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/package-info.java
@@ -0,0 +1,21 @@
+/**
+ * RMI daemon implementation. A variation of an RMI registry.
+ * @author Donal Fellows
+ */
+package org.taverna.server.rmidaemon;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/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
deleted file mode 100644
index 333153f..0000000
--- a/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.taverna.server.rmidaemon;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 520b928..0000000
--- a/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * RMI daemon implementation. A variation of an RMI registry.
- * @author Donal Fellows
- */
-package org.taverna.server.rmidaemon;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/IllegalStateTransitionException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/IllegalStateTransitionException.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/IllegalStateTransitionException.java
new file mode 100644
index 0000000..cb0cc0a
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/IllegalStateTransitionException.java
@@ -0,0 +1,49 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/ImplementationException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/ImplementationException.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/ImplementationException.java
new file mode 100644
index 0000000..3e33fc7
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/ImplementationException.java
@@ -0,0 +1,39 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectory.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectory.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectory.java
new file mode 100644
index 0000000..229d0b7
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectory.java
@@ -0,0 +1,75 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectoryEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectoryEntry.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectoryEntry.java
new file mode 100644
index 0000000..9b77e79
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectoryEntry.java
@@ -0,0 +1,75 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteFile.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteFile.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteFile.java
new file mode 100644
index 0000000..63778db
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteFile.java
@@ -0,0 +1,111 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteInput.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteInput.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteInput.java
new file mode 100644
index 0000000..b4fda9e
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteInput.java
@@ -0,0 +1,105 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteListener.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteListener.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteListener.java
new file mode 100644
index 0000000..2539f0d
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteListener.java
@@ -0,0 +1,90 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteRunFactory.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteRunFactory.java
new file mode 100644
index 0000000..bc91f0e
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteRunFactory.java
@@ -0,0 +1,97 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSecurityContext.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSecurityContext.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSecurityContext.java
new file mode 100644
index 0000000..fc4baff
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSecurityContext.java
@@ -0,0 +1,47 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSingleRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSingleRun.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSingleRun.java
new file mode 100644
index 0000000..e2519f8
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSingleRun.java
@@ -0,0 +1,267 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteStatus.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteStatus.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteStatus.java
new file mode 100644
index 0000000..89a7cff
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteStatus.java
@@ -0,0 +1,53 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+/**
+ * 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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/StillWorkingOnItException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/StillWorkingOnItException.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/StillWorkingOnItException.java
new file mode 100644
index 0000000..a7af96b
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/StillWorkingOnItException.java
@@ -0,0 +1,33 @@
+/*
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */
+
+/**
+ * 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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/package-info.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/package-info.java
new file mode 100644
index 0000000..6466e2f
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/package-info.java
@@ -0,0 +1,22 @@
+/*
+ */
+/**
+ * Interfaces exported by worker classes to the server.
+ */
+package org.taverna.server.localworker.remote;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/UsageRecordReceiver.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/UsageRecordReceiver.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/UsageRecordReceiver.java
new file mode 100644
index 0000000..cc0127e
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/UsageRecordReceiver.java
@@ -0,0 +1,42 @@
+/*
+ */
+package org.taverna.server.localworker.server;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/package-info.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/package-info.java
new file mode 100644
index 0000000..584f1ed
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/package-info.java
@@ -0,0 +1,22 @@
+/*
+ */
+/**
+ * Interfaces exported by the server to worker classes.
+ */
+package org.taverna.server.localworker.server;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/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
deleted file mode 100644
index cb0cc0a..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 3e33fc7..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 229d0b7..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 9b77e79..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 63778db..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index b4fda9e..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 2539f0d..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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;
-}



[04/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
deleted file mode 100644
index b61fc10..0000000
--- a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.taverna.server.master.mocks;
-/*
- * 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.
- */
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-public class MockPolicy extends SimpleServerPolicy {
-	public MockPolicy() {
-		super();
-		super.setCleanerInterval(30);
-	}
-
-	public int maxruns = 10;
-	Integer usermaxruns;
-	Set<TavernaRun> denyaccess = new HashSet<>();
-	boolean exnOnUpdate, exnOnCreate, exnOnDelete;
-
-	@Override
-	public int getMaxRuns() {
-		return maxruns;
-	}
-
-	@Override
-	public Integer getMaxRuns(UsernamePrincipal user) {
-		return usermaxruns;
-	}
-
-	@Override
-	public boolean permitAccess(UsernamePrincipal user, TavernaRun run) {
-		return !denyaccess.contains(run);
-	}
-
-	@Override
-	public void permitCreate(UsernamePrincipal user, Workflow workflow)
-			throws NoCreateException {
-		if (this.exnOnCreate)
-			throw new NoCreateException();
-	}
-
-	@Override
-	public void permitDestroy(UsernamePrincipal user, TavernaRun run)
-			throws NoDestroyException {
-		if (this.exnOnDelete)
-			throw new NoDestroyException();
-	}
-
-	@Override
-	public void permitUpdate(UsernamePrincipal user, TavernaRun run)
-			throws NoUpdateException {
-		if (this.exnOnUpdate)
-			throw new NoUpdateException();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
deleted file mode 100644
index 7d9c998..0000000
--- a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package org.taverna.server.master.mocks;
-/*
- * 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.
- */
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * A factory for event listener. The factory is configured using Spring.
- * 
- * @author Donal Fellows
- */
-public class SimpleListenerFactory implements ListenerFactory {
-	private Map<String, Builder> builders = new HashMap<>();
-
-	public void setBuilders(Map<String, Builder> builders) {
-		this.builders = builders;
-	}
-
-	@Override
-	public List<String> getSupportedListenerTypes() {
-		return new ArrayList<>(builders.keySet());
-	}
-
-	@Override
-	public Listener makeListener(TavernaRun run, String listenerType,
-			String configuration) throws NoListenerException {
-		Builder b = builders.get(listenerType);
-		if (b == null)
-			throw new NoListenerException("no such listener type");
-		Listener l = b.build(run, configuration);
-		run.addListener(l);
-		return l;
-	}
-
-	/**
-	 * How to actually construct a listener.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public interface Builder {
-		/**
-		 * Make an event listener attached to a run.
-		 * 
-		 * @param run
-		 *            The run to attach to.
-		 * @param configuration
-		 *            A user-specified configuration document. The constructed
-		 *            listener <i>should</i> process this configuration document
-		 *            and be able to return it to the user when requested.
-		 * @return The listener object.
-		 * @throws NoListenerException
-		 *             If the listener construction failed or the
-		 *             <b>configuration</b> document was bad in some way.
-		 */
-		public Listener build(TavernaRun run, String configuration)
-				throws NoListenerException;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
deleted file mode 100644
index 63b6754..0000000
--- a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package org.taverna.server.master.mocks;
-/*
- * 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.
- */
-
-import java.lang.ref.WeakReference;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Example of a store for Taverna Workflow Runs.
- * 
- * @author Donal Fellows
- */
-public class SimpleNonpersistentRunStore implements RunStore {
-	private Map<String, TavernaRun> store = new HashMap<>();
-	private Object lock = new Object();
-
-	Timer timer;
-	private CleanerTask cleaner;
-
-	/**
-	 * The connection to the main policy store. Suitable for wiring up with
-	 * Spring.
-	 * 
-	 * @param p
-	 *            The policy to connect to.
-	 */
-	public void setPolicy(SimpleServerPolicy p) {
-		p.store = this;
-		cleanerIntervalUpdated(p.getCleanerInterval());
-	}
-
-	public SimpleNonpersistentRunStore() {
-		timer = new Timer("SimpleNonpersistentRunStore.CleanerTimer", true);
-		cleanerIntervalUpdated(300);
-	}
-
-	@Override
-	protected void finalize() {
-		timer.cancel();
-	}
-
-	/**
-	 * Remove and destroy all runs that are expired at the moment that this
-	 * method starts.
-	 */
-	void clean() {
-		Date now = new Date();
-		synchronized (lock) {
-			// Use an iterator so we have access to its remove() method...
-			Iterator<TavernaRun> i = store.values().iterator();
-			while (i.hasNext()) {
-				TavernaRun w = i.next();
-				if (w.getExpiry().before(now)) {
-					i.remove();
-					try {
-						w.destroy();
-					} catch (NoDestroyException e) {
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * Reconfigure the cleaner task's call interval. This is called internally
-	 * and from the Policy when the interval is set there.
-	 * 
-	 * @param intervalInSeconds
-	 *            How long between runs of the cleaner task, in seconds.
-	 */
-	void cleanerIntervalUpdated(int intervalInSeconds) {
-		if (cleaner != null)
-			cleaner.cancel();
-		cleaner = new CleanerTask(this, intervalInSeconds);
-	}
-
-	@Override
-	public TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
-			throws UnknownRunException {
-		synchronized (lock) {
-			TavernaRun w = store.get(uuid);
-			if (w == null || !p.permitAccess(user, w))
-				throw new UnknownRunException();
-			return w;
-		}
-	}
-
-	@Override
-	public TavernaRun getRun(String uuid) throws UnknownRunException {
-		synchronized (lock) {
-			TavernaRun w = store.get(uuid);
-			if (w == null)
-				throw new UnknownRunException();
-			return w;
-		}
-	}
-
-	@Override
-	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
-		Map<String, TavernaRun> filtered = new HashMap<>();
-		synchronized (lock) {
-			for (Map.Entry<String, TavernaRun> entry : store.entrySet())
-				if (p.permitAccess(user, entry.getValue()))
-					filtered.put(entry.getKey(), entry.getValue());
-		}
-		return filtered;
-	}
-
-	@Override
-	public String registerRun(TavernaRun run) {
-		synchronized (lock) {
-			store.put(run.getId(), run);
-			return run.getId();
-		}
-	}
-
-	@Override
-	public void unregisterRun(String uuid) {
-		synchronized (lock) {
-			store.remove(uuid);
-		}
-	}
-}
-
-class CleanerTask extends TimerTask {
-	WeakReference<SimpleNonpersistentRunStore> store;
-
-	CleanerTask(SimpleNonpersistentRunStore store, int interval) {
-		this.store = new WeakReference<>(store);
-		int tms = interval * 1000;
-		store.timer.scheduleAtFixedRate(this, tms, tms);
-	}
-
-	@Override
-	public void run() {
-		SimpleNonpersistentRunStore s = store.get();
-		if (s != null) {
-			s.clean();
-		}
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
deleted file mode 100644
index 8dd2757..0000000
--- a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.taverna.server.master.mocks;
-/*
- * 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.
- */
-
-import java.net.URI;
-import java.util.List;
-
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A very simple (and unsafe) security model. The number of runs is configurable
- * through Spring (or 10 if unconfigured) with no per-user limits supported, all
- * workflows are permitted, and all identified users may create a workflow run.
- * Any user may read off information about any run, but only its owner may
- * modify or destroy it.
- * <p>
- * Note that this is a <i>Policy Enforcement Point</i> for access control to
- * individual workflows.
- * 
- * @author Donal Fellows
- */
-public class SimpleServerPolicy implements Policy {
-	private int maxRuns = 10;
-	private int cleanerInterval;
-	SimpleNonpersistentRunStore store;
-
-	public void setMaxRuns(int maxRuns) {
-		this.maxRuns = maxRuns;
-	}
-
-	@Override
-	public int getMaxRuns() {
-		return maxRuns;
-	}
-
-	@Override
-	public Integer getMaxRuns(UsernamePrincipal p) {
-		return null; // No per-user limits
-	}
-
-	public int getCleanerInterval() {
-		return cleanerInterval;
-	}
-
-	/**
-	 * Sets how often the store of workflow runs will try to clean out expired
-	 * runs.
-	 * 
-	 * @param intervalInSeconds
-	 */
-	public void setCleanerInterval(int intervalInSeconds) {
-		cleanerInterval = intervalInSeconds;
-		if (store != null)
-			store.cleanerIntervalUpdated(intervalInSeconds);
-	}
-
-	@Override
-	public boolean permitAccess(UsernamePrincipal p, TavernaRun run) {
-		// No secrets here!
-		return true;
-	}
-
-	@Override
-	public void permitCreate(UsernamePrincipal p, Workflow workflow)
-			throws NoCreateException {
-		// Only identified users may create
-		if (p == null)
-			throw new NoCreateException();
-		// Global run count limit enforcement
-		if (store.listRuns(p, this).size() >= maxRuns)
-			throw new NoCreateException();
-		// Per-user run count enforcement would come here
-	}
-
-	@Override
-	public void permitDestroy(UsernamePrincipal p, TavernaRun run)
-			throws NoDestroyException {
-		// Only the creator may destroy
-		if (p == null || !p.equals(run.getSecurityContext().getOwner()))
-			throw new NoDestroyException();
-	}
-
-	@Override
-	public void permitUpdate(UsernamePrincipal p, TavernaRun run)
-			throws NoUpdateException {
-		// Only the creator may change
-		if (p == null || !p.equals(run.getSecurityContext().getOwner()))
-			throw new NoUpdateException();
-	}
-
-	@Override
-	public int getOperatingLimit() {
-		return 1;
-	}
-
-	@Override
-	public List<URI> listPermittedWorkflowURIs(UsernamePrincipal user) {
-		return null;
-	}
-
-	@Override
-	public void setPermittedWorkflowURIs(UsernamePrincipal user,
-			List<URI> permitted) {
-		// Ignore
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Constants.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Constants.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Constants.java
new file mode 100644
index 0000000..4ee24ad
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Constants.java
@@ -0,0 +1,154 @@
+/*
+ */
+package org.taverna.server.localworker.api;
+/*
+ * 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.
+ */
+
+import static java.nio.charset.Charset.defaultCharset;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * The defaults associated with this worker, together with various other
+ * constants.
+ * 
+ * @author Donal Fellows
+ */
+public abstract class Constants {
+	/**
+	 * Subdirectories of the working directory to create by default.
+	 */
+	public static final String[] SUBDIR_LIST = { "conf", "externaltool", "feed",
+			"interactions", "lib", "logs", "plugins", "repository", "var" };
+
+	/** The name of the default encoding for characters on this machine. */
+	public static final String SYSTEM_ENCODING = defaultCharset().name();
+
+	/**
+	 * Password to use to encrypt security information. This default is <7 chars
+	 * to work even without Unlimited Strength JCE.
+	 */
+	public static final char[] KEYSTORE_PASSWORD = { 'c', 'h', 'a', 'n', 'g', 'e' };
+
+	/**
+	 * The name of the directory (in the home directory) where security settings
+	 * will be written.
+	 */
+	public static final String SECURITY_DIR_NAME = ".taverna-server-security";
+
+	/** The name of the file that will be the created keystore. */
+	public static final String KEYSTORE_FILE = "t2keystore.ubr";
+
+	/** The name of the file that will be the created truststore. */
+	public static final String TRUSTSTORE_FILE = "t2truststore.ubr";
+
+	/**
+	 * The name of the file that contains the password to unlock the keystore
+	 * and truststore.
+	 */
+	public static final String PASSWORD_FILE = "password.txt";
+
+	// --------- UNUSED ---------
+	// /**
+	// * The name of the file that contains the mapping from URIs to keystore
+	// * aliases.
+	// */
+	// public static final String URI_ALIAS_MAP = "urlmap.txt";
+
+	/**
+	 * Used to instruct the Taverna credential manager to use a non-default
+	 * location for user credentials.
+	 */
+	public static final String CREDENTIAL_MANAGER_DIRECTORY = "-cmdir";
+
+	/**
+	 * Used to instruct the Taverna credential manager to take its master
+	 * password from standard input.
+	 */
+	public static final String CREDENTIAL_MANAGER_PASSWORD = "-cmpassword";
+
+	/**
+	 * Name of environment variable used to pass HELIO security tokens to
+	 * workflows.
+	 */
+	// This technique is known to be insecure; bite me.
+	public static final String HELIO_TOKEN_NAME = "HELIO_CIS_TOKEN";
+
+	/**
+	 * The name of the standard listener, which is installed by default.
+	 */
+	public static final String DEFAULT_LISTENER_NAME = "io";
+
+	/**
+	 * Time to wait for the subprocess to wait, in milliseconds.
+	 */
+	public static final int START_WAIT_TIME = 1500;
+
+	/**
+	 * Time to wait for success or failure of a death-causing activity (i.e.,
+	 * sending a signal).
+	 */
+	public static final int DEATH_TIME = 333;
+
+	/**
+	 * The name of the file (in this code's resources) that provides the default
+	 * security policy that we use.
+	 */
+	public static final String SECURITY_POLICY_FILE = "security.policy";
+
+	/**
+	 * The Java property holding security policy info.
+	 */
+	public static final String SEC_POLICY_PROP = "java.security.policy";
+	/**
+	 * The Java property to set to make this code not try to enforce security
+	 * policy.
+	 */
+	public static final String UNSECURE_PROP = "taverna.suppressrestrictions.rmi";
+	/**
+	 * The Java property that holds the name of the host name to enforce.
+	 */
+	public static final String RMI_HOST_PROP = "java.rmi.server.hostname";
+	/**
+	 * The default hostname to require in secure mode. This is the
+	 * <i>resolved</i> version of "localhost".
+	 */
+	public static final String LOCALHOST;
+	static {
+		String h = "127.0.0.1"; // fallback
+		try {
+			h = InetAddress.getByName("localhost").getHostAddress();
+		} catch (UnknownHostException e) {
+			e.printStackTrace();
+		} finally {
+			LOCALHOST = h;
+		}
+	}
+
+	/**
+	 * Time to wait during closing down this process. In milliseconds.
+	 */
+	public static final int DEATH_DELAY = 500;
+	/**
+	 * The name of the property describing where shared directories should be
+	 * located.
+	 */
+	public static final String SHARED_DIR_PROP = "taverna.sharedDirectory";
+
+	public static final String TIME = "/usr/bin/time";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/RunAccounting.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/RunAccounting.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/RunAccounting.java
new file mode 100644
index 0000000..dd18db0
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/RunAccounting.java
@@ -0,0 +1,35 @@
+/*
+ */
+package org.taverna.server.localworker.api;
+/*
+ * 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.
+ */
+
+/**
+ * 
+ * @author Donal Fellows
+ */
+public interface RunAccounting {
+	/**
+	 * Logs that a run has started executing.
+	 */
+	void runStarted();
+
+	/**
+	 * Logs that a run has finished executing.
+	 */
+	void runCeased();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Worker.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Worker.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Worker.java
new file mode 100644
index 0000000..52c7009
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Worker.java
@@ -0,0 +1,148 @@
+/*
+ */
+package org.taverna.server.localworker.api;
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import org.taverna.server.localworker.impl.LocalWorker;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+/**
+ * The interface between the connectivity layer and the thunk to the
+ * subprocesses.
+ * 
+ * @author Donal Fellows
+ */
+public interface Worker {
+	/**
+	 * Fire up the workflow. This causes a transition into the operating state.
+	 * 
+	 * @param local
+	 *            The reference to the factory class for this worker.
+	 * @param executeWorkflowCommand
+	 *            The command to run to execute the workflow.
+	 * @param workflow
+	 *            The workflow document to execute.
+	 * @param workingDir
+	 *            What directory to use as the working directory.
+	 * @param inputBaclavaFile
+	 *            The baclava file to use for inputs, or <tt>null</tt> to use
+	 *            the other <b>input*</b> arguments' values.
+	 * @param inputRealFiles
+	 *            A mapping of input names to files that supply them. Note that
+	 *            we assume that nothing mapped here will be mapped in
+	 *            <b>inputValues</b>.
+	 * @param inputValues
+	 *            A mapping of input names to values to supply to them. Note
+	 *            that we assume that nothing mapped here will be mapped in
+	 *            <b>inputFiles</b>.
+	 * @param inputDelimiters
+	 *            A mapping of input names to characters used to split them into
+	 *            lists.
+	 * @param outputBaclavaFile
+	 *            What baclava file to write the output from the workflow into,
+	 *            or <tt>null</tt> to have it written into the <tt>out</tt>
+	 *            subdirectory.
+	 * @param contextDirectory
+	 *            The directory containing the keystore and truststore. <i>Must
+	 *            not be <tt>null</tt>.</i>
+	 * @param keystorePassword
+	 *            The password to the keystore and truststore. <i>Must not be
+	 *            <tt>null</tt>.</i>
+	 * @param generateProvenance
+	 *            Whether to generate a run bundle containing provenance data.
+	 * @param environment
+	 *            Any environment variables that need to be added to the
+	 *            invokation.
+	 * @param masterToken
+	 *            The internal name of the workflow run.
+	 * @param runtimeSettings
+	 *            List of configuration details for the forked runtime.
+	 * @return Whether a successful start happened.
+	 * @throws Exception
+	 *             If any of quite a large number of things goes wrong.
+	 */
+	boolean initWorker(LocalWorker local, String executeWorkflowCommand,
+			byte[] workflow, File workingDir, File inputBaclavaFile,
+			Map<String, File> inputRealFiles, Map<String, String> inputValues,
+			Map<String, String> inputDelimiters, File outputBaclavaFile,
+			File contextDirectory, char[] keystorePassword,
+			boolean generateProvenance, Map<String, String> environment,
+			String masterToken, List<String> runtimeSettings) throws Exception;
+
+	/**
+	 * Kills off the subprocess if it exists and is alive.
+	 * 
+	 * @throws Exception
+	 *             if anything goes badly wrong when the worker is being killed
+	 *             off.
+	 */
+	void killWorker() throws Exception;
+
+	/**
+	 * Move the worker out of the stopped state and back to operating.
+	 * 
+	 * @throws Exception
+	 *             if it fails (which it always does; operation currently
+	 *             unsupported).
+	 */
+	void startWorker() throws Exception;
+
+	/**
+	 * Move the worker into the stopped state from the operating state.
+	 * 
+	 * @throws Exception
+	 *             if it fails (which it always does; operation currently
+	 *             unsupported).
+	 */
+	void stopWorker() throws Exception;
+
+	/**
+	 * @return The status of the workflow run. Note that this can be an
+	 *         expensive operation.
+	 */
+	RemoteStatus getWorkerStatus();
+
+	/**
+	 * @return The listener that is registered by default, in addition to all
+	 *         those that are explicitly registered by the user.
+	 */
+	RemoteListener getDefaultListener();
+
+	/**
+	 * @param receiver
+	 *            The destination where any final usage records are to be
+	 *            written in order to log them back to the server.
+	 */
+	void setURReceiver(UsageRecordReceiver receiver);
+
+	/**
+	 * Arrange for the deletion of any resources created during worker process
+	 * construction. Guaranteed to be the last thing done before finalization.
+	 * 
+	 * @throws ImplementationException
+	 *             If anything goes wrong.
+	 */
+	void deleteLocalResources() throws ImplementationException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/WorkerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/WorkerFactory.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/WorkerFactory.java
new file mode 100644
index 0000000..0fd2d20
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/WorkerFactory.java
@@ -0,0 +1,34 @@
+package org.taverna.server.localworker.api;
+/*
+ * 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.
+ */
+
+
+/**
+ * Class that manufactures instances of {@link Worker}.
+ * 
+ * @author Donal Fellows
+ */
+public interface WorkerFactory {
+	/**
+	 * Create an instance of the low-level worker class.
+	 * 
+	 * @return The worker object.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	Worker makeInstance() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/DirectoryDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/DirectoryDelegate.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/DirectoryDelegate.java
new file mode 100644
index 0000000..6b7ba77
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/DirectoryDelegate.java
@@ -0,0 +1,174 @@
+/*
+ */
+package org.taverna.server.localworker.impl;
+/*
+ * 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.
+ */
+
+import static org.apache.commons.io.FileUtils.forceDelete;
+import static org.apache.commons.io.FileUtils.forceMkdir;
+import static org.apache.commons.io.FileUtils.touch;
+import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedNewFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.collections.MapIterator;
+import org.apache.commons.collections.map.ReferenceMap;
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
+import org.taverna.server.localworker.remote.RemoteFile;
+
+/**
+ * This class acts as a remote-aware delegate for the workflow run's working
+ * directory and its subdirectories.
+ * 
+ * @author Donal Fellows
+ * @see FileDelegate
+ */
+@SuppressWarnings("serial")
+public class DirectoryDelegate extends UnicastRemoteObject implements
+		RemoteDirectory {
+	private File dir;
+	private DirectoryDelegate parent;
+	private ReferenceMap localCache;
+
+	/**
+	 * @param dir
+	 * @param parent
+	 * @throws RemoteException
+	 *             If registration of the directory fails.
+	 */
+	public DirectoryDelegate(@Nonnull File dir,
+			@Nonnull DirectoryDelegate parent) throws RemoteException {
+		super();
+		this.localCache = new ReferenceMap();
+		this.dir = dir;
+		this.parent = parent;
+	}
+
+	@Override
+	public Collection<RemoteDirectoryEntry> getContents()
+			throws RemoteException {
+		List<RemoteDirectoryEntry> result = new ArrayList<>();
+		for (String s : dir.list()) {
+			if (s.equals(".") || s.equals(".."))
+				continue;
+			File f = new File(dir, s);
+			RemoteDirectoryEntry entry;
+			synchronized (localCache) {
+				entry = (RemoteDirectoryEntry) localCache.get(s);
+				if (f.isDirectory()) {
+					if (entry == null || !(entry instanceof DirectoryDelegate)) {
+						entry = new DirectoryDelegate(f, this);
+						localCache.put(s, entry);
+					}
+				} else if (f.isFile()) {
+					if (entry == null || !(entry instanceof FileDelegate)) {
+						entry = new FileDelegate(f, this);
+						localCache.put(s, entry);
+					}
+				} else {
+					// not file or dir; skip...
+					continue;
+				}
+			}
+			result.add(entry);
+		}
+		return result;
+	}
+
+	@Override
+	public RemoteFile makeEmptyFile(String name) throws IOException {
+		File f = getValidatedNewFile(dir, name);
+		touch(f);
+		FileDelegate delegate = new FileDelegate(f, this);
+		synchronized (localCache) {
+			localCache.put(name, delegate);
+		}
+		return delegate;
+	}
+
+	@Override
+	public RemoteDirectory makeSubdirectory(String name) throws IOException {
+		File f = getValidatedNewFile(dir, name);
+		forceMkdir(f);
+		DirectoryDelegate delegate = new DirectoryDelegate(f, this);
+		synchronized (localCache) {
+			localCache.put(name, delegate);
+		}
+		return delegate;
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public void destroy() throws IOException {
+		if (parent == null)
+			throw new IOException("tried to destroy main job working directory");
+		Collection<RemoteDirectoryEntry> values;
+		synchronized (localCache) {
+			values = new ArrayList<>(localCache.values());
+		}
+		for (RemoteDirectoryEntry obj : values) {
+			if (obj == null)
+				continue;
+			try {
+				obj.destroy();
+			} catch (IOException e) {
+			}
+		}
+		forceDelete(dir);
+		parent.forgetEntry(this);
+	}
+
+	@Override
+	public RemoteDirectory getContainingDirectory() {
+		return parent;
+	}
+
+	void forgetEntry(@Nonnull RemoteDirectoryEntry entry) {
+		synchronized (localCache) {
+			MapIterator i = localCache.mapIterator();
+			while (i.hasNext()) {
+				Object key = i.next();
+				if (entry == i.getValue()) {
+					localCache.remove(key);
+					break;
+				}
+			}
+		}
+	}
+
+	@Override
+	public String getName() {
+		if (parent == null)
+			return "";
+		return dir.getName();
+	}
+
+	@Override
+	public Date getModificationDate() throws RemoteException {
+		return new Date(dir.lastModified());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/FileDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/FileDelegate.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/FileDelegate.java
new file mode 100644
index 0000000..8dd9ede
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/FileDelegate.java
@@ -0,0 +1,155 @@
+/*
+ */
+package org.taverna.server.localworker.impl;
+/*
+ * 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.
+ */
+
+import static java.lang.System.arraycopy;
+import static java.net.InetAddress.getLocalHost;
+import static org.apache.commons.io.FileUtils.copyFile;
+import static org.apache.commons.io.FileUtils.forceDelete;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Date;
+
+import javax.annotation.Nonnull;
+
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteFile;
+
+/**
+ * This class acts as a remote-aware delegate for the files in a workflow run's
+ * working directory and its subdirectories.
+ * 
+ * @author Donal Fellows
+ * @see DirectoryDelegate
+ */
+@java.lang.SuppressWarnings("serial")
+public class FileDelegate extends UnicastRemoteObject implements RemoteFile {
+	private File file;
+	private DirectoryDelegate parent;
+
+	/**
+	 * @param file
+	 * @param parent
+	 * @throws RemoteException
+	 *             If registration of the file fails.
+	 */
+	public FileDelegate(@Nonnull File file, @Nonnull DirectoryDelegate parent)
+			throws RemoteException {
+		super();
+		this.file = file;
+		this.parent = parent;
+	}
+
+	@Override
+	public byte[] getContents(int offset, int length) throws IOException {
+		if (length == -1)
+			length = (int) (file.length() - offset);
+		if (length < 0 || length > 1024 * 64)
+			length = 1024 * 64;
+		byte[] buffer = new byte[length];
+		int read;
+		try (FileInputStream fis = new FileInputStream(file)) {
+			if (offset > 0 && fis.skip(offset) != offset)
+				throw new IOException("did not move to correct offset in file");
+			read = fis.read(buffer);
+		}
+		if (read <= 0)
+			return new byte[0];
+		if (read < buffer.length) {
+			byte[] shortened = new byte[read];
+			arraycopy(buffer, 0, shortened, 0, read);
+			return shortened;
+		}
+		return buffer;
+	}
+
+	@Override
+	public long getSize() {
+		return file.length();
+	}
+
+	@Override
+	public void setContents(byte[] data) throws IOException {
+		try (FileOutputStream fos = new FileOutputStream(file)) {
+			fos.write(data);
+		}
+	}
+
+	@Override
+	public void appendContents(byte[] data) throws IOException {
+		try (FileOutputStream fos = new FileOutputStream(file, true)) {
+			fos.write(data);
+		}
+	}
+
+	@Override
+	public void destroy() throws IOException {
+		forceDelete(file);
+		parent.forgetEntry(this);
+		parent = null;
+	}
+
+	@Override
+	public RemoteDirectory getContainingDirectory() {
+		return parent;
+	}
+
+	@Override
+	public String getName() {
+		return file.getName();
+	}
+
+	@Override
+	public void copy(RemoteFile sourceFile) throws RemoteException, IOException {
+		String sourceHost = sourceFile.getNativeHost();
+		if (!getNativeHost().equals(sourceHost)) {
+			throw new IOException(
+					"cross-system copy not implemented; cannot copy from "
+							+ sourceHost + " to " + getNativeHost());
+		}
+		// Must copy; cannot count on other file to stay unmodified
+		copyFile(new File(sourceFile.getNativeName()), file);
+	}
+
+	@Override
+	public String getNativeName() {
+		return file.getAbsolutePath();
+	}
+
+	@Override
+	public String getNativeHost() {
+		try {
+			return getLocalHost().getHostAddress();
+		} catch (UnknownHostException e) {
+			throw new RuntimeException(
+					"unexpected failure to resolve local host address", e);
+		}
+	}
+
+	@Override
+	public Date getModificationDate() throws RemoteException {
+		return new Date(file.lastModified());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/LocalWorker.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/LocalWorker.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/LocalWorker.java
new file mode 100644
index 0000000..f96f91c
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/LocalWorker.java
@@ -0,0 +1,782 @@
+/*
+ */
+package org.taverna.server.localworker.impl;
+/*
+ * 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.
+ */
+
+import static java.lang.Runtime.getRuntime;
+import static java.lang.System.getProperty;
+import static java.lang.System.out;
+import static java.lang.management.ManagementFactory.getRuntimeMXBean;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static java.util.UUID.randomUUID;
+import static org.apache.commons.io.FileUtils.forceDelete;
+import static org.apache.commons.io.FileUtils.forceMkdir;
+import static org.apache.commons.io.FileUtils.writeByteArrayToFile;
+import static org.apache.commons.io.FileUtils.writeLines;
+import static org.taverna.server.localworker.api.Constants.HELIO_TOKEN_NAME;
+import static org.taverna.server.localworker.api.Constants.KEYSTORE_FILE;
+import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
+import static org.taverna.server.localworker.api.Constants.SECURITY_DIR_NAME;
+import static org.taverna.server.localworker.api.Constants.SHARED_DIR_PROP;
+import static org.taverna.server.localworker.api.Constants.SUBDIR_LIST;
+import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
+import static org.taverna.server.localworker.api.Constants.TRUSTSTORE_FILE;
+import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedFile;
+import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
+import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
+import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
+import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import org.taverna.server.localworker.api.Worker;
+import org.taverna.server.localworker.api.WorkerFactory;
+import org.taverna.server.localworker.remote.IllegalStateTransitionException;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteInput;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteSecurityContext;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.remote.StillWorkingOnItException;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+/**
+ * This class implements one side of the connection between the Taverna Server
+ * master server and this process. It delegates to a {@link Worker} instance the
+ * handling of actually running a workflow.
+ * 
+ * @author Donal Fellows
+ * @see DirectoryDelegate
+ * @see FileDelegate
+ * @see WorkerCore
+ */
+@SuppressWarnings("serial")
+public class LocalWorker extends UnicastRemoteObject implements RemoteSingleRun {
+	// ----------------------- CONSTANTS -----------------------
+
+	/** Handle to the directory containing the security info. */
+	static final File SECURITY_DIR;
+	static final String SLASHTEMP;
+	static {
+		SLASHTEMP = getProperty("java.io.tmpdir");
+		File home = new File(getProperty("user.home"));
+		// If we can't write to $HOME (i.e., we're in an odd deployment) use
+		// the official version of /tmp/$PID as a fallback.
+		if (!home.canWrite())
+			home = new File(SLASHTEMP, getRuntimeMXBean().getName());
+		SECURITY_DIR = new File(home, SECURITY_DIR_NAME);
+	}
+
+	// ----------------------- VARIABLES -----------------------
+
+	/**
+	 * Magic flag used to turn off problematic code when testing inside CI
+	 * environment.
+	 */
+	static boolean DO_MKDIR = true;
+
+	/** What to use to run a workflow engine. */
+	private final String executeWorkflowCommand;
+	/** What workflow to run. */
+	private final byte[] workflow;
+	/** The remote access object for the working directory. */
+	private final DirectoryDelegate baseDir;
+	/** What inputs to pass as files. */
+	final Map<String, String> inputFiles;
+	/** What inputs to pass as files (as file refs). */
+	final Map<String, File> inputRealFiles;
+	/** What inputs to pass as direct values. */
+	final Map<String, String> inputValues;
+	/** What delimiters to use. */
+	final Map<String, String> inputDelimiters;
+	/** The interface to the workflow engine subprocess. */
+	private final Worker core;
+	/** Our descriptor token (UUID). */
+	private final String masterToken;
+	/**
+	 * The root working directory for a workflow run, or <tt>null</tt> if it has
+	 * been deleted.
+	 */
+	private File base;
+	/**
+	 * When did this workflow start running, or <tt>null</tt> for
+	 * "never/not yet".
+	 */
+	private Date start;
+	/**
+	 * When did this workflow finish running, or <tt>null</tt> for
+	 * "never/not yet".
+	 */
+	private Date finish;
+	/** The cached status of the workflow run. */
+	RemoteStatus status;
+	/**
+	 * The name of the input Baclava document, or <tt>null</tt> to not do it
+	 * that way.
+	 */
+	String inputBaclava;
+	/**
+	 * The name of the output Baclava document, or <tt>null</tt> to not do it
+	 * that way.
+	 */
+	String outputBaclava;
+	/**
+	 * The file containing the input Baclava document, or <tt>null</tt> to not
+	 * do it that way.
+	 */
+	private File inputBaclavaFile;
+	/**
+	 * The file containing the output Baclava document, or <tt>null</tt> to not
+	 * do it that way.
+	 */
+	private File outputBaclavaFile;
+	/**
+	 * Registered shutdown hook so that we clean up when this process is killed
+	 * off, or <tt>null</tt> if that is no longer necessary.
+	 */
+	Thread shutdownHook;
+	/** Location for security information to be written to. */
+	File securityDirectory;
+	/**
+	 * Password to use to encrypt security information.
+	 */
+	char[] keystorePassword = KEYSTORE_PASSWORD;
+	/** Additional server-specified environment settings. */
+	Map<String, String> environment = new HashMap<>();
+	/** Additional server-specified java runtime settings. */
+	List<String> runtimeSettings = new ArrayList<>();
+	URL interactionFeedURL;
+	URL webdavURL;
+	URL publishURL;//FIXME
+	private boolean doProvenance = true;
+
+	// ----------------------- METHODS -----------------------
+
+	/**
+	 * @param executeWorkflowCommand
+	 *            The script used to execute workflows.
+	 * @param workflow
+	 *            The workflow to execute.
+	 * @param workerClass
+	 *            The class to instantiate as our local representative of the
+	 *            run.
+	 * @param urReceiver
+	 *            The remote class to report the generated usage record(s) to.
+	 * @param id
+	 *            The UUID to use, or <tt>null</tt> if we are to invent one.
+	 * @param seedEnvironment
+	 *            The key/value pairs to seed the worker subprocess environment
+	 *            with.
+	 * @param javaParams
+	 *            Parameters to pass to the worker subprocess java runtime
+	 *            itself.
+	 * @param workerFactory
+	 *            How to make instances of the low-level worker objects.
+	 * @throws RemoteException
+	 *             If registration of the worker fails.
+	 * @throws ImplementationException
+	 *             If something goes wrong during local setup.
+	 */
+	protected LocalWorker(String executeWorkflowCommand, byte[] workflow,
+			UsageRecordReceiver urReceiver, UUID id,
+			Map<String, String> seedEnvironment, List<String> javaParams,
+			WorkerFactory workerFactory) throws RemoteException,
+			ImplementationException {
+		super();
+		if (id == null)
+			id = randomUUID();
+		masterToken = id.toString();
+		this.workflow = workflow;
+		this.executeWorkflowCommand = executeWorkflowCommand;
+		String sharedDir = getProperty(SHARED_DIR_PROP, SLASHTEMP);
+		base = new File(sharedDir, masterToken);
+		out.println("about to create " + base);
+		try {
+			forceMkdir(base);
+			for (String subdir : SUBDIR_LIST) {
+				new File(base, subdir).mkdir();
+			}
+		} catch (IOException e) {
+			throw new ImplementationException(
+					"problem creating run working directory", e);
+		}
+		baseDir = new DirectoryDelegate(base, null);
+		inputFiles = new HashMap<>();
+		inputRealFiles = new HashMap<>();
+		inputValues = new HashMap<>();
+		inputDelimiters = new HashMap<>();
+		environment.putAll(seedEnvironment);
+		runtimeSettings.addAll(javaParams);
+		try {
+			core = workerFactory.makeInstance();
+		} catch (Exception e) {
+			out.println("problem when creating core worker implementation");
+			e.printStackTrace(out);
+			throw new ImplementationException(
+					"problem when creating core worker implementation", e);
+		}
+		core.setURReceiver(urReceiver);
+		Thread t = new Thread(new Runnable() {
+			/**
+			 * Kill off the worker launched by the core.
+			 */
+			@Override
+			public void run() {
+				try {
+					shutdownHook = null;
+					destroy();
+				} catch (ImplementationException e) {
+					// Absolutely nothing we can do here
+				}
+			}
+		});
+		getRuntime().addShutdownHook(t);
+		shutdownHook = t;
+		status = Initialized;
+	}
+
+	@Override
+	public void destroy() throws ImplementationException {
+		killWorkflowSubprocess();
+		removeFromShutdownHooks();
+		// Is this it?
+		deleteWorkingDirectory();
+		deleteSecurityManagerDirectory();
+		core.deleteLocalResources();
+	}
+
+	private void killWorkflowSubprocess() {
+		if (status != Finished && status != Initialized)
+			try {
+				core.killWorker();
+				if (finish == null)
+					finish = new Date();
+			} catch (Exception e) {
+				out.println("problem when killing worker");
+				e.printStackTrace(out);
+			}
+	}
+
+	private void removeFromShutdownHooks() throws ImplementationException {
+		try {
+			if (shutdownHook != null)
+				getRuntime().removeShutdownHook(shutdownHook);
+		} catch (RuntimeException e) {
+			throw new ImplementationException("problem removing shutdownHook",
+					e);
+		} finally {
+			shutdownHook = null;
+		}
+	}
+
+	private void deleteWorkingDirectory() throws ImplementationException {
+		try {
+			if (base != null)
+				forceDelete(base);
+		} catch (IOException e) {
+			out.println("problem deleting working directory");
+			e.printStackTrace(out);
+			throw new ImplementationException(
+					"problem deleting working directory", e);
+		} finally {
+			base = null;
+		}
+	}
+
+	private void deleteSecurityManagerDirectory()
+			throws ImplementationException {
+		try {
+			if (securityDirectory != null)
+				forceDelete(securityDirectory);
+		} catch (IOException e) {
+			out.println("problem deleting security directory");
+			e.printStackTrace(out);
+			throw new ImplementationException(
+					"problem deleting security directory", e);
+		} finally {
+			securityDirectory = null;
+		}
+	}
+
+	@Override
+	public void addListener(RemoteListener listener) throws RemoteException,
+			ImplementationException {
+		throw new ImplementationException("not implemented");
+	}
+
+	@Override
+	public String getInputBaclavaFile() {
+		return inputBaclava;
+	}
+
+	@Override
+	public List<RemoteInput> getInputs() throws RemoteException {
+		ArrayList<RemoteInput> result = new ArrayList<>();
+		for (String name : inputFiles.keySet())
+			result.add(new InputDelegate(name));
+		return result;
+	}
+
+	@Override
+	public List<String> getListenerTypes() {
+		return emptyList();
+	}
+
+	@Override
+	public List<RemoteListener> getListeners() {
+		return singletonList(core.getDefaultListener());
+	}
+
+	@Override
+	public String getOutputBaclavaFile() {
+		return outputBaclava;
+	}
+
+	class SecurityDelegate extends UnicastRemoteObject implements
+			RemoteSecurityContext {
+		private void setPrivatePerms(File dir) {
+			if (!dir.setReadable(false, false) || !dir.setReadable(true, true)
+					|| !dir.setExecutable(false, false)
+					|| !dir.setExecutable(true, true)
+					|| !dir.setWritable(false, false)
+					|| !dir.setWritable(true, true)) {
+				out.println("warning: "
+						+ "failed to set permissions on security context directory");
+			}
+		}
+
+		protected SecurityDelegate(String token) throws IOException {
+			super();
+			if (DO_MKDIR) {
+				securityDirectory = new File(SECURITY_DIR, token);
+				forceMkdir(securityDirectory);
+				setPrivatePerms(securityDirectory);
+			}
+		}
+
+		/**
+		 * Write some data to a given file in the context directory.
+		 * 
+		 * @param name
+		 *            The name of the file to write.
+		 * @param data
+		 *            The bytes to put in the file.
+		 * @throws RemoteException
+		 *             If anything goes wrong.
+		 * @throws ImplementationException
+		 */
+		protected void write(String name, byte[] data) throws RemoteException,
+				ImplementationException {
+			try {
+				File f = new File(securityDirectory, name);
+				writeByteArrayToFile(f, data);
+			} catch (IOException e) {
+				throw new ImplementationException("problem writing " + name, e);
+			}
+		}
+
+		/**
+		 * Write some data to a given file in the context directory.
+		 * 
+		 * @param name
+		 *            The name of the file to write.
+		 * @param data
+		 *            The lines to put in the file. The
+		 *            {@linkplain LocalWorker#SYSTEM_ENCODING system encoding}
+		 *            will be used to do the writing.
+		 * @throws RemoteException
+		 *             If anything goes wrong.
+		 * @throws ImplementationException
+		 */
+		protected void write(String name, Collection<String> data)
+				throws RemoteException, ImplementationException {
+			try {
+				File f = new File(securityDirectory, name);
+				writeLines(f, SYSTEM_ENCODING, data);
+			} catch (IOException e) {
+				throw new ImplementationException("problem writing " + name, e);
+			}
+		}
+
+		/**
+		 * Write some data to a given file in the context directory.
+		 * 
+		 * @param name
+		 *            The name of the file to write.
+		 * @param data
+		 *            The line to put in the file. The
+		 *            {@linkplain LocalWorker#SYSTEM_ENCODING system encoding}
+		 *            will be used to do the writing.
+		 * @throws RemoteException
+		 *             If anything goes wrong.
+		 * @throws ImplementationException
+		 */
+		protected void write(String name, char[] data) throws RemoteException,
+				ImplementationException {
+			try {
+				File f = new File(securityDirectory, name);
+				writeLines(f, SYSTEM_ENCODING, asList(new String(data)));
+			} catch (IOException e) {
+				throw new ImplementationException("problem writing " + name, e);
+			}
+		}
+
+		@Override
+		public void setKeystore(byte[] keystore) throws RemoteException,
+				ImplementationException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			if (keystore == null)
+				throw new IllegalArgumentException("keystore may not be null");
+			write(KEYSTORE_FILE, keystore);
+		}
+
+		@Override
+		public void setPassword(char[] password) throws RemoteException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			if (password == null)
+				throw new IllegalArgumentException("password may not be null");
+			keystorePassword = password.clone();
+		}
+
+		@Override
+		public void setTruststore(byte[] truststore) throws RemoteException,
+				ImplementationException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			if (truststore == null)
+				throw new IllegalArgumentException("truststore may not be null");
+			write(TRUSTSTORE_FILE, truststore);
+		}
+
+		@Override
+		public void setUriToAliasMap(Map<URI, String> uriToAliasMap)
+				throws RemoteException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			if (uriToAliasMap == null)
+				return;
+			ArrayList<String> lines = new ArrayList<>();
+			for (Entry<URI, String> site : uriToAliasMap.entrySet())
+				lines.add(site.getKey().toASCIIString() + " " + site.getValue());
+			// write(URI_ALIAS_MAP, lines);
+		}
+
+		@Override
+		public void setHelioToken(String helioToken) throws RemoteException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			out.println("registering HELIO CIS token for export");
+			environment.put(HELIO_TOKEN_NAME, helioToken);
+		}
+	}
+
+	@Override
+	public RemoteSecurityContext getSecurityContext() throws RemoteException,
+			ImplementationException {
+		try {
+			return new SecurityDelegate(masterToken);
+		} catch (RemoteException e) {
+			if (e.getCause() != null)
+				throw new ImplementationException(
+						"problem initializing security context", e.getCause());
+			throw e;
+		} catch (IOException e) {
+			throw new ImplementationException(
+					"problem initializing security context", e);
+		}
+	}
+
+	@Override
+	public RemoteStatus getStatus() {
+		// only state that can spontaneously change to another
+		if (status == Operating) {
+			status = core.getWorkerStatus();
+			if (status == Finished && finish == null)
+				finish = new Date();
+		}
+		return status;
+	}
+
+	@Override
+	public RemoteDirectory getWorkingDirectory() {
+		return baseDir;
+	}
+
+	File validateFilename(String filename) throws RemoteException {
+		if (filename == null)
+			throw new IllegalArgumentException("filename must be non-null");
+		try {
+			return getValidatedFile(base, filename.split("/"));
+		} catch (IOException e) {
+			throw new IllegalArgumentException("failed to validate filename", e);
+		}
+	}
+
+	class InputDelegate extends UnicastRemoteObject implements RemoteInput {
+		private String name;
+
+		InputDelegate(String name) throws RemoteException {
+			super();
+			this.name = name;
+			if (!inputFiles.containsKey(name)) {
+				if (status != Initialized)
+					throw new IllegalStateException("not initializing");
+				inputFiles.put(name, null);
+				inputRealFiles.put(name, null);
+				inputValues.put(name, null);
+				inputDelimiters.put(name, null);
+			}
+		}
+
+		@Override
+		public String getFile() {
+			return inputFiles.get(name);
+		}
+
+		@Override
+		public String getName() {
+			return name;
+		}
+
+		@Override
+		public String getValue() {
+			return inputValues.get(name);
+		}
+
+		@Override
+		public String getDelimiter() throws RemoteException {
+			return inputDelimiters.get(name);
+		}
+
+		@Override
+		public void setFile(String file) throws RemoteException {
+			if (status != Initialized)
+				throw new IllegalStateException("not initializing");
+			inputRealFiles.put(name, validateFilename(file));
+			inputValues.put(name, null);
+			inputFiles.put(name, file);
+			inputBaclava = null;
+		}
+
+		@Override
+		public void setValue(String value) throws RemoteException {
+			if (status != Initialized)
+				throw new IllegalStateException("not initializing");
+			inputValues.put(name, value);
+			inputFiles.put(name, null);
+			inputRealFiles.put(name, null);
+			inputBaclava = null;
+		}
+
+		@Override
+		public void setDelimiter(String delimiter) throws RemoteException {
+			if (status != Initialized)
+				throw new IllegalStateException("not initializing");
+			if (inputBaclava != null)
+				throw new IllegalStateException("input baclava file set");
+			if (delimiter != null) {
+				if (delimiter.length() > 1)
+					throw new IllegalStateException(
+							"multi-character delimiter not permitted");
+				if (delimiter.charAt(0) == 0)
+					throw new IllegalStateException(
+							"may not use NUL for splitting");
+				if (delimiter.charAt(0) > 127)
+					throw new IllegalStateException(
+							"only ASCII characters supported for splitting");
+			}
+			inputDelimiters.put(name, delimiter);
+		}
+	}
+
+	@Override
+	public RemoteInput makeInput(String name) throws RemoteException {
+		return new InputDelegate(name);
+	}
+
+	@Override
+	public RemoteListener makeListener(String type, String configuration)
+			throws RemoteException {
+		throw new RemoteException("listener manufacturing unsupported");
+	}
+
+	@Override
+	public void setInputBaclavaFile(String filename) throws RemoteException {
+		if (status != Initialized)
+			throw new IllegalStateException("not initializing");
+		inputBaclavaFile = validateFilename(filename);
+		for (String input : inputFiles.keySet()) {
+			inputFiles.put(input, null);
+			inputRealFiles.put(input, null);
+			inputValues.put(input, null);
+		}
+		inputBaclava = filename;
+	}
+
+	@Override
+	public void setOutputBaclavaFile(String filename) throws RemoteException {
+		if (status != Initialized)
+			throw new IllegalStateException("not initializing");
+		if (filename != null)
+			outputBaclavaFile = validateFilename(filename);
+		else
+			outputBaclavaFile = null;
+		outputBaclava = filename;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean prov) {
+		doProvenance = prov;
+	}
+
+	@Override
+	public void setStatus(RemoteStatus newStatus)
+			throws IllegalStateTransitionException, RemoteException,
+			ImplementationException, StillWorkingOnItException {
+		if (status == newStatus)
+			return;
+
+		switch (newStatus) {
+		case Initialized:
+			throw new IllegalStateTransitionException(
+					"may not move back to start");
+		case Operating:
+			switch (status) {
+			case Initialized:
+				boolean started;
+				try {
+					started = createWorker();
+				} catch (Exception e) {
+					throw new ImplementationException(
+							"problem creating executing workflow", e);
+				}
+				if (!started)
+					throw new StillWorkingOnItException(
+							"workflow start in process");
+				break;
+			case Stopped:
+				try {
+					core.startWorker();
+				} catch (Exception e) {
+					throw new ImplementationException(
+							"problem continuing workflow run", e);
+				}
+				break;
+			case Finished:
+				throw new IllegalStateTransitionException("already finished");
+			default:
+				break;
+			}
+			status = Operating;
+			break;
+		case Stopped:
+			switch (status) {
+			case Initialized:
+				throw new IllegalStateTransitionException(
+						"may only stop from Operating");
+			case Operating:
+				try {
+					core.stopWorker();
+				} catch (Exception e) {
+					throw new ImplementationException(
+							"problem stopping workflow run", e);
+				}
+				break;
+			case Finished:
+				throw new IllegalStateTransitionException("already finished");
+			default:
+				break;
+			}
+			status = Stopped;
+			break;
+		case Finished:
+			switch (status) {
+			case Operating:
+			case Stopped:
+				try {
+					core.killWorker();
+					if (finish == null)
+						finish = new Date();
+				} catch (Exception e) {
+					throw new ImplementationException(
+							"problem killing workflow run", e);
+				}
+			default:
+				break;
+			}
+			status = Finished;
+			break;
+		}
+	}
+
+	private boolean createWorker() throws Exception {
+		start = new Date();
+		char[] pw = keystorePassword;
+		keystorePassword = null;
+		/*
+		 * Do not clear the keystorePassword array here; its ownership is
+		 * *transferred* to the worker core which doesn't copy it but *does*
+		 * clear it after use.
+		 */
+		return core.initWorker(this, executeWorkflowCommand, workflow, base,
+				inputBaclavaFile, inputRealFiles, inputValues, inputDelimiters,
+				outputBaclavaFile, securityDirectory, pw, doProvenance,
+				environment, masterToken, runtimeSettings);
+	}
+
+	@Override
+	public Date getFinishTimestamp() {
+		return finish == null ? null : new Date(finish.getTime());
+	}
+
+	@Override
+	public Date getStartTimestamp() {
+		return start == null ? null : new Date(start.getTime());
+	}
+
+	@Override
+	public void setInteractionServiceDetails(URL feed, URL webdav, URL publish) {
+		interactionFeedURL = feed;
+		webdavURL = webdav;
+		publishURL = publish;
+	}
+
+	@Override
+	public void ping() {
+		// Do nothing here; this *should* be empty
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/TavernaRunManager.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/TavernaRunManager.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/TavernaRunManager.java
new file mode 100644
index 0000000..167302c
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/TavernaRunManager.java
@@ -0,0 +1,255 @@
+/*
+ */
+package org.taverna.server.localworker.impl;
+/*
+ * 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.
+ */
+
+import static java.lang.Runtime.getRuntime;
+import static java.lang.System.exit;
+import static java.lang.System.getProperty;
+import static java.lang.System.out;
+import static java.lang.System.setProperty;
+import static java.lang.System.setSecurityManager;
+import static java.rmi.registry.LocateRegistry.getRegistry;
+import static org.taverna.server.localworker.api.Constants.DEATH_DELAY;
+import static org.taverna.server.localworker.api.Constants.LOCALHOST;
+import static org.taverna.server.localworker.api.Constants.RMI_HOST_PROP;
+import static org.taverna.server.localworker.api.Constants.SECURITY_POLICY_FILE;
+import static org.taverna.server.localworker.api.Constants.SEC_POLICY_PROP;
+import static org.taverna.server.localworker.api.Constants.UNSECURE_PROP;
+
+import java.io.ByteArrayInputStream;
+import java.net.URI;
+import java.rmi.RemoteException;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
+import org.taverna.server.localworker.api.RunAccounting;
+import org.taverna.server.localworker.api.Worker;
+import org.taverna.server.localworker.api.WorkerFactory;
+import org.taverna.server.localworker.remote.RemoteRunFactory;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+
+/**
+ * The registered factory for runs, this class is responsible for constructing
+ * runs that are suitable for particular users. It is also the entry point for
+ * this whole process.
+ * 
+ * @author Donal Fellows
+ * @see LocalWorker
+ */
+@SuppressWarnings("serial")
+public class TavernaRunManager extends UnicastRemoteObject implements
+		RemoteRunFactory, RunAccounting, WorkerFactory {
+	String command;
+	Map<String, String> seedEnvironment = new HashMap<>();
+	List<String> javaInitParams = new ArrayList<>();
+	private WorkflowBundleIO io;
+	private int activeRuns = 0;
+	// Hacks!
+	public static String interactionHost;
+	public static String interactionPort;
+	public static String interactionWebdavPath;
+	public static String interactionFeedPath;
+
+	/**
+	 * How to get the actual workflow document from the XML document that it is
+	 * contained in.
+	 * 
+	 * @param containerDocument
+	 *            The document sent from the web interface.
+	 * @return The element describing the workflow, as expected by the Taverna
+	 *         command line executor.
+	 */
+	protected Element unwrapWorkflow(Document containerDocument) {
+		return (Element) containerDocument.getDocumentElement().getFirstChild();
+	}
+
+	private static final String usage = "java -jar server.worker.jar workflowExecScript ?-Ekey=val...? ?-Jconfig? UUID";
+
+	/**
+	 * An RMI-enabled factory for runs.
+	 * 
+	 * @param command
+	 *            What command to call to actually run a run.
+	 * @throws RemoteException
+	 *             If anything goes wrong during creation of the instance.
+	 */
+	public TavernaRunManager(String command) throws RemoteException {
+		this.command = command;
+		this.io = new WorkflowBundleIO();
+	}
+
+	@Override
+	public RemoteSingleRun make(byte[] workflow, String creator,
+			UsageRecordReceiver urReceiver, UUID id) throws RemoteException {
+		if (creator == null)
+			throw new RemoteException("no creator");
+		try {
+			URI wfid = io.readBundle(new ByteArrayInputStream(workflow), null)
+					.getMainWorkflow().getIdentifier();
+			out.println("Creating run from workflow <" + wfid + "> for <"
+					+ creator + ">");
+			return new LocalWorker(command, workflow, urReceiver, id,
+					seedEnvironment, javaInitParams, this);
+		} catch (RemoteException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new RemoteException("bad instance construction", e);
+		}
+	}
+
+	private static boolean shuttingDown;
+	private static String factoryName;
+	private static Registry registry;
+
+	static synchronized void unregisterFactory() {
+		if (!shuttingDown) {
+			shuttingDown = true;
+			try {
+				if (factoryName != null && registry != null)
+					registry.unbind(factoryName);
+			} catch (Exception e) {
+				e.printStackTrace(out);
+			}
+		}
+	}
+
+	@Override
+	public void shutdown() {
+		unregisterFactory();
+		new Thread(new DelayedDeath()).start();
+	}
+
+	static class DelayedDeath implements Runnable {
+		@Override
+		public void run() {
+			try {
+				Thread.sleep(DEATH_DELAY);
+			} catch (InterruptedException e) {
+			} finally {
+				exit(0);
+			}
+		}
+	}
+
+	private void addArgument(String arg) {
+		if (arg.startsWith("-E")) {
+			String trimmed = arg.substring(2);
+			int idx = trimmed.indexOf('=');
+			if (idx > 0) {
+				addEnvironmentDefinition(trimmed.substring(0, idx),
+						trimmed.substring(idx + 1));
+				return;
+			}
+		} else if (arg.startsWith("-D")) {
+			if (arg.indexOf('=') > 0) {
+				addJavaParameter(arg);
+				return;
+			}
+		} else if (arg.startsWith("-J")) {
+			addJavaParameter(arg.substring(2));
+			return;
+		}
+		throw new IllegalArgumentException("argument \"" + arg
+				+ "\" must start with -D, -E or -J; "
+				+ "-D and -E must contain a \"=\"");
+	}
+
+	/**
+	 * @param args
+	 *            The arguments from the command line invocation.
+	 * @throws Exception
+	 *             If we can't connect to the RMI registry, or if we can't read
+	 *             the workflow, or if we can't build the worker instance, or
+	 *             register it. Also if the arguments are wrong.
+	 */
+	public static void main(String[] args) throws Exception {
+		if (args.length < 2)
+			throw new Exception("wrong # args: must be \"" + usage + "\"");
+		if (!getProperty(UNSECURE_PROP, "no").equals("yes")) {
+			setProperty(SEC_POLICY_PROP, LocalWorker.class.getClassLoader()
+					.getResource(SECURITY_POLICY_FILE).toExternalForm());
+			setProperty(RMI_HOST_PROP, LOCALHOST);
+		}
+		setSecurityManager(new SecurityManager());
+		factoryName = args[args.length - 1];
+		TavernaRunManager man = new TavernaRunManager(args[0]);
+		for (int i = 1; i < args.length - 1; i++)
+			man.addArgument(args[i]);
+		registry = getRegistry(LOCALHOST);
+
+		registry.bind(factoryName, man);
+		getRuntime().addShutdownHook(new Thread() {
+			@Override
+			public void run() {
+				unregisterFactory();
+			}
+		});
+		out.println("registered RemoteRunFactory with ID " + factoryName);
+	}
+
+	private void addJavaParameter(String string) {
+		this.javaInitParams.add(string);
+	}
+
+	private void addEnvironmentDefinition(String key, String value) {
+		this.seedEnvironment.put(key, value);
+	}
+
+	@Override
+	public void setInteractionServiceDetails(String host, String port,
+			String webdavPath, String feedPath) throws RemoteException {
+		if (host == null || port == null || webdavPath == null
+				|| feedPath == null)
+			throw new IllegalArgumentException("all params must be non-null");
+		interactionHost = host;
+		interactionPort = port;
+		interactionWebdavPath = webdavPath;
+		interactionFeedPath = feedPath;
+	}
+
+	@Override
+	public synchronized int countOperatingRuns() {
+		return (activeRuns < 0 ? 0 : activeRuns);
+	}
+
+	@Override
+	public synchronized void runStarted() {
+		activeRuns++;
+	}
+
+	@Override
+	public synchronized void runCeased() {
+		activeRuns--;
+	}
+
+	@Override
+	public Worker makeInstance() throws Exception {
+		return new WorkerCore(this);
+	}
+}


[38/42] incubator-taverna-server git commit: package org.apache.taverna.server.*

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/FileContents.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/FileContents.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/FileContents.java
index fa9978b..179483b 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/FileContents.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/FileContents.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.soap;
+package org.apache.taverna.server.master.soap;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -31,8 +31,8 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlMimeType;
 import javax.xml.bind.annotation.XmlType;
 
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.interfaces.File;
 
 /**
  * An MTOM-capable description of how to transfer the contents of a file.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/PermissionList.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/PermissionList.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/PermissionList.java
index 6568ab2..05c069c 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/PermissionList.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/PermissionList.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.soap;
+package org.apache.taverna.server.master.soap;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 
-import org.taverna.server.master.common.Permission;
+import org.apache.taverna.server.master.common.Permission;
 
 /**
  * The list of permissions to access a workflow run of users <i>other than the

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/TavernaServerSOAP.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/TavernaServerSOAP.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/TavernaServerSOAP.java
index f41539c..6d70fe1 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/TavernaServerSOAP.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/TavernaServerSOAP.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.soap;
+package org.apache.taverna.server.master.soap;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,8 +18,8 @@ package org.taverna.server.master.soap;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.Roles.USER;
 
 import java.net.URI;
 import java.util.Date;
@@ -34,30 +34,30 @@ import javax.xml.bind.annotation.XmlElement;
 
 import org.apache.cxf.annotations.WSDLDocumentation;
 import org.apache.taverna.server.usagerecord.JobUsageRecord;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.common.InputDescription;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoCredentialException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.NotOwnerException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.rest.TavernaServerREST;
-import org.taverna.server.port_description.OutputDescription;
+import org.apache.taverna.server.master.common.Capability;
+import org.apache.taverna.server.master.common.Credential;
+import org.apache.taverna.server.master.common.DirEntryReference;
+import org.apache.taverna.server.master.common.InputDescription;
+import org.apache.taverna.server.master.common.Permission;
+import org.apache.taverna.server.master.common.ProfileList;
+import org.apache.taverna.server.master.common.RunReference;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Trust;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.common.version.Version;
+import org.apache.taverna.server.master.exceptions.BadPropertyValueException;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.InvalidCredentialException;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoCredentialException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.NotOwnerException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.rest.TavernaServerREST;
+import org.apache.taverna.server.port_description.OutputDescription;
 
 /**
  * The SOAP service interface to Taverna 3 Server.
@@ -309,7 +309,7 @@ public interface TavernaServerSOAP {
 	 */
 	@WebResult(name = "RunInputDescriptor")
 	@WSDLDocumentation("Get a description of what inputs the given workflow run expects to receive.")
-	org.taverna.server.port_description.InputDescription getRunInputDescriptor(
+	org.apache.taverna.server.port_description.InputDescription getRunInputDescriptor(
 			@WebParam(name = "runName") @XmlElement(required = true) String runName)
 			throws UnknownRunException;
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/WrappedWorkflow.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/WrappedWorkflow.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/WrappedWorkflow.java
index 745876d..5639531 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/WrappedWorkflow.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/WrappedWorkflow.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.soap;
+package org.apache.taverna.server.master.soap;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -34,7 +34,7 @@ import javax.xml.bind.annotation.XmlMimeType;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
-import org.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.common.Workflow;
 
 import org.apache.taverna.scufl2.api.io.ReaderException;
 import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/ZippedDirectory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/ZippedDirectory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/ZippedDirectory.java
index 5b2d261..6bd593f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/ZippedDirectory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/ZippedDirectory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.soap;
+package org.apache.taverna.server.master.soap;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.soap;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
+import static org.apache.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -31,8 +31,8 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlMimeType;
 import javax.xml.bind.annotation.XmlType;
 
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.interfaces.Directory;
 
 /**
  * An MTOM-capable description of how to transfer the zipped contents of a

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/package-info.java
index cd753b7..7187129 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/package-info.java
@@ -12,7 +12,7 @@
 		@XmlNs(prefix = "port", namespaceURI = DATA),
 		@XmlNs(prefix = "feed", namespaceURI = FEED),
 		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.soap;
+package org.apache.taverna.server.master.soap;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -31,13 +31,13 @@ package org.taverna.server.master.soap;
  */
 
 import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.port_description.Namespaces.DATA;
+import static org.apache.taverna.server.master.common.Namespaces.ADMIN;
+import static org.apache.taverna.server.master.common.Namespaces.FEED;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.port_description.Namespaces.DATA;
 
 import javax.xml.bind.annotation.XmlNs;
 import javax.xml.bind.annotation.XmlSchema;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecord.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecord.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecord.java
index b1f0602..07e61d6 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecord.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecord.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.usage;
+package org.apache.taverna.server.master.usage;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecordRecorder.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecordRecorder.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecordRecorder.java
index 18aeb3b..0acb052 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecordRecorder.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecordRecorder.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.usage;
+package org.apache.taverna.server.master.usage;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -32,9 +32,9 @@ import javax.xml.bind.JAXBException;
 import org.apache.commons.logging.Log;
 import org.apache.taverna.server.usagerecord.JobUsageRecord;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.utils.Contextualizer;
-import org.taverna.server.master.utils.JDOSupport;
+import org.apache.taverna.server.master.api.ManagementModel;
+import org.apache.taverna.server.master.utils.Contextualizer;
+import org.apache.taverna.server.master.utils.JDOSupport;
 
 /**
  * A simple state-aware writer of usage records. It just appends them, one by

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/package-info.java
index a7fe733..fa3f9d7 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/package-info.java
@@ -3,7 +3,7 @@
 /**
  * Resource usage recording mechanism.
  */
-package org.taverna.server.master.usage;
+package org.apache.taverna.server.master.usage;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimeLogger.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimeLogger.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimeLogger.java
index 4452935..724a1d9 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimeLogger.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimeLogger.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@ import static java.lang.System.nanoTime;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.apache.taverna.server.master.TavernaServer.JMX_ROOT;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
@@ -35,7 +35,7 @@ import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
 import org.springframework.jmx.export.annotation.ManagedAttribute;
 import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.master.common.version.Version;
+import org.apache.taverna.server.master.common.version.Version;
 
 /**
  * This class is responsible for timing all invocations of publicly-exposed
@@ -73,7 +73,7 @@ public class CallTimeLogger {
 	 *             If anything goes wrong with the wrapped call.
 	 * @see System#nanoTime()
 	 */
-	@Around("@annotation(org.taverna.server.master.utils.CallTimeLogger.PerfLogged)")
+	@Around("@annotation(org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged)")
 	public Object time(ProceedingJoinPoint call) throws Throwable {
 		long fore = nanoTime();
 		try {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimingFilter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimingFilter.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimingFilter.java
index d8ad78d..1d5942b 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimingFilter.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimingFilter.java
@@ -1,7 +1,7 @@
 /**
  * 
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CapabilityLister.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CapabilityLister.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CapabilityLister.java
index 1387e05..1d01518 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CapabilityLister.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CapabilityLister.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -26,7 +26,7 @@ import java.util.Properties;
 
 import javax.annotation.PostConstruct;
 
-import org.taverna.server.master.common.Capability;
+import org.apache.taverna.server.master.common.Capability;
 
 /**
  * Utility for listing the capabilities supported by this Taverna Server

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CertificateChainFetcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CertificateChainFetcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CertificateChainFetcher.java
index 76ef017..ff21e82 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CertificateChainFetcher.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CertificateChainFetcher.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/Contextualizer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/Contextualizer.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/Contextualizer.java
index e0ee4d1..7e465dc 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/Contextualizer.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/Contextualizer.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,7 +22,7 @@ import javax.servlet.ServletContext;
 import javax.ws.rs.core.UriInfo;
 
 import org.springframework.web.context.ServletContextAware;
-import org.taverna.server.master.common.version.Version;
+import org.apache.taverna.server.master.common.version.Version;
 
 /**
  * Convert a string (URL, etc) to a version that is contextualized to the

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/DerbyUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/DerbyUtils.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/DerbyUtils.java
index e4be90b..eec5475 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/DerbyUtils.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/DerbyUtils.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FilenameUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FilenameUtils.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FilenameUtils.java
index 3c39326..848217e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FilenameUtils.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FilenameUtils.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,13 +22,13 @@ import java.util.List;
 
 import javax.ws.rs.core.PathSegment;
 
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.common.DirEntryReference;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.interfaces.DirectoryEntry;
+import org.apache.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
 
 /**
  * Utility functions for getting entries from directories.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
index 7f5f92a..3a5ef0f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/InvocationCounter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/InvocationCounter.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/InvocationCounter.java
index 0600857..3420a27 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/InvocationCounter.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/InvocationCounter.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -39,7 +39,7 @@ import org.aspectj.lang.annotation.Before;
 public class InvocationCounter {
 	private int count;
 
-	@Before("@annotation(org.taverna.server.master.utils.InvocationCounter.CallCounted)")
+	@Before("@annotation(org.apache.taverna.server.master.utils.InvocationCounter.CallCounted)")
 	public synchronized void count() {
 		count++;
 	}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JCECheck.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JCECheck.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JCECheck.java
index 7f248ff..ccd2dc3 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JCECheck.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JCECheck.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JDOSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JDOSupport.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JDOSupport.java
index 96f6a11..5e3ed61 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JDOSupport.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JDOSupport.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -187,7 +187,7 @@ public abstract class JDOSupport<T> {
 		private Log log = getLog("Taverna.Server.Utils");
 		private volatile int txid;
 
-		@Around(value = "@annotation(org.taverna.server.master.utils.JDOSupport.WithinSingleTransaction) && target(support)", argNames = "support")
+		@Around(value = "@annotation(org.apache.taverna.server.master.utils.JDOSupport.WithinSingleTransaction) && target(support)", argNames = "support")
 		Object applyTransaction(ProceedingJoinPoint pjp, JDOSupport<?> support)
 				throws Throwable {
 			synchronized (lock) {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/LoggingDerbyAdapter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/LoggingDerbyAdapter.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/LoggingDerbyAdapter.java
index 8bd0506..75564d4 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/LoggingDerbyAdapter.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/LoggingDerbyAdapter.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/OneShotThread.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/OneShotThread.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/OneShotThread.java
index 32cca5a..a025aa5 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/OneShotThread.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/OneShotThread.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RestUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RestUtils.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RestUtils.java
index d69612e..c68ecc9 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RestUtils.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RestUtils.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RuntimeExceptionWrapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RuntimeExceptionWrapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RuntimeExceptionWrapper.java
index 333febe..093d2d8 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RuntimeExceptionWrapper.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RuntimeExceptionWrapper.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,7 +20,7 @@ package org.taverna.server.master.utils;
 
 import org.aspectj.lang.annotation.AfterThrowing;
 import org.aspectj.lang.annotation.Aspect;
-import org.taverna.server.master.exceptions.GeneralFailureException;
+import org.apache.taverna.server.master.exceptions.GeneralFailureException;
 
 /**
  * Aspect used to convert {@linkplain RuntimeException runtime exceptions} into
@@ -39,7 +39,7 @@ public class RuntimeExceptionWrapper {
 	 * @throws GeneralFailureException
 	 *             The known exception type that it is mapped to.
 	 */
-	@AfterThrowing(pointcut = "execution(* org.taverna.server.master.rest..*(..)) && !bean(*Provider.*)", throwing = "exn")
+	@AfterThrowing(pointcut = "execution(* org.apache.taverna.server.master.rest..*(..)) && !bean(*Provider.*)", throwing = "exn")
 	public void wrapRuntimeException(RuntimeException exn)
 			throws GeneralFailureException {
 		// Exclude security-related exceptions

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/UsernamePrincipal.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/UsernamePrincipal.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/UsernamePrincipal.java
index 25cf64f..541917a 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/UsernamePrincipal.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/UsernamePrincipal.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
index 1bd2a95..2ace683 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WebappAwareDataSource.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WebappAwareDataSource.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WebappAwareDataSource.java
index 24246b5..15b7929 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WebappAwareDataSource.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WebappAwareDataSource.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,7 +21,7 @@ package org.taverna.server.master.utils;
 import static java.lang.Thread.currentThread;
 import static java.sql.DriverManager.deregisterDriver;
 import static java.sql.DriverManager.getDrivers;
-import static org.taverna.server.master.utils.Contextualizer.ROOT_PLACEHOLDER;
+import static org.apache.taverna.server.master.utils.Contextualizer.ROOT_PLACEHOLDER;
 
 import java.io.PrintWriter;
 import java.sql.Connection;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/X500Utils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/X500Utils.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/X500Utils.java
index d258079..0a52262 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/X500Utils.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/X500Utils.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/package-info.java
index 64a9f68..05ddd60 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/package-info.java
@@ -4,7 +4,7 @@
  * Miscellaneous utility classes. Includes aspects that might be attached
  * for purposes such as transaction management and invocation tracking.
  */
-package org.taverna.server.master.utils;
+package org.apache.taverna.server.master.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/CompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/CompletionNotifier.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/CompletionNotifier.java
index 1868f94..d13f09e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/CompletionNotifier.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/CompletionNotifier.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/FactoryBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/FactoryBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/FactoryBean.java
index d38f0cc..a9556df 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/FactoryBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/FactoryBean.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.worker;
  * limitations under the License.
  */
 
-import org.taverna.server.master.notification.atom.EventDAO;
+import org.apache.taverna.server.master.notification.atom.EventDAO;
 
 /**
  * What the remote run really needs of its factory.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PasswordIssuer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PasswordIssuer.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PasswordIssuer.java
index 649db64..99b1ee1 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PasswordIssuer.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PasswordIssuer.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyImpl.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyImpl.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyImpl.java
index 37d5760..3312499 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyImpl.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyImpl.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.worker;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
+import static org.apache.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
 
 import java.net.URI;
 import java.util.List;
@@ -29,15 +29,15 @@ import org.springframework.beans.factory.annotation.Required;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.taverna.server.master.common.Roles;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.common.Roles;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoDestroyException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.Policy;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * Basic policy implementation that allows any workflow to be instantiated by

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyLimits.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyLimits.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyLimits.java
index 43c0aa4..a6134aa 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyLimits.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyLimits.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,7 +21,7 @@ package org.taverna.server.master.worker;
 import java.net.URI;
 import java.util.List;
 
-import org.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Status;
 
 /**
  * The worker policy delegates certain limits to the state model of the

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RemoteRunDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RemoteRunDelegate.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RemoteRunDelegate.java
index fb1ac47..6a8c63e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RemoteRunDelegate.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RemoteRunDelegate.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,8 +25,8 @@ import static java.util.Collections.unmodifiableSet;
 import static java.util.UUID.randomUUID;
 import static org.apache.commons.io.IOUtils.closeQuietly;
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.worker.RemoteRunDelegate.checkBadFilename;
-import static org.taverna.server.master.worker.RunConnection.NAME_LENGTH;
+import static org.apache.taverna.server.master.worker.RemoteRunDelegate.checkBadFilename;
+import static org.apache.taverna.server.master.worker.RunConnection.NAME_LENGTH;
 
 import java.io.IOException;
 import java.io.ObjectInputStream;
@@ -52,33 +52,33 @@ import java.util.zip.ZipOutputStream;
 import javax.annotation.Nonnull;
 
 import org.apache.commons.logging.Log;
-import org.taverna.server.localworker.remote.IllegalStateTransitionException;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
-import org.taverna.server.localworker.remote.RemoteFile;
-import org.taverna.server.localworker.remote.RemoteInput;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.remote.StillWorkingOnItException;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.OverloadedException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.localworker.remote.IllegalStateTransitionException;
+import org.apache.taverna.server.localworker.remote.ImplementationException;
+import org.apache.taverna.server.localworker.remote.RemoteDirectory;
+import org.apache.taverna.server.localworker.remote.RemoteDirectoryEntry;
+import org.apache.taverna.server.localworker.remote.RemoteFile;
+import org.apache.taverna.server.localworker.remote.RemoteInput;
+import org.apache.taverna.server.localworker.remote.RemoteListener;
+import org.apache.taverna.server.localworker.remote.RemoteSingleRun;
+import org.apache.taverna.server.localworker.remote.RemoteStatus;
+import org.apache.taverna.server.localworker.remote.StillWorkingOnItException;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.BadPropertyValueException;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.OverloadedException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.interfaces.DirectoryEntry;
+import org.apache.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.interfaces.Input;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.SecurityContextFactory;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * Bridging shim between the WebApp world and the RMI world.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunConnection.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunConnection.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunConnection.java
index 0c2b1a9..dce0284 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunConnection.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunConnection.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,12 +20,12 @@ package org.taverna.server.master.worker;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
-import static org.taverna.server.master.worker.RunConnection.COUNT_QUERY;
-import static org.taverna.server.master.worker.RunConnection.NAMES_QUERY;
-import static org.taverna.server.master.worker.RunConnection.SCHEMA;
-import static org.taverna.server.master.worker.RunConnection.TABLE;
-import static org.taverna.server.master.worker.RunConnection.TIMEOUT_QUERY;
-import static org.taverna.server.master.worker.RunConnection.UNTERMINATED_QUERY;
+import static org.apache.taverna.server.master.worker.RunConnection.COUNT_QUERY;
+import static org.apache.taverna.server.master.worker.RunConnection.NAMES_QUERY;
+import static org.apache.taverna.server.master.worker.RunConnection.SCHEMA;
+import static org.apache.taverna.server.master.worker.RunConnection.TABLE;
+import static org.apache.taverna.server.master.worker.RunConnection.TIMEOUT_QUERY;
+import static org.apache.taverna.server.master.worker.RunConnection.UNTERMINATED_QUERY;
 
 import java.io.IOException;
 import java.rmi.MarshalledObject;
@@ -42,12 +42,12 @@ import javax.jdo.annotations.PrimaryKey;
 import javax.jdo.annotations.Queries;
 import javax.jdo.annotations.Query;
 
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.localworker.remote.RemoteSingleRun;
+import org.apache.taverna.server.master.common.Credential;
+import org.apache.taverna.server.master.common.Trust;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.interfaces.SecurityContextFactory;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * The representation of the connections to the runs that actually participates
@@ -228,7 +228,7 @@ public class RunConnection {
 			run = new MarshalledObject<>(rrd.run);
 			securityContextFactory = rrd.getSecurityContext().getFactory();
 			owner = rrd.getSecurityContext().getOwner().getName();
-			securityToken = ((org.taverna.server.master.worker.SecurityContextFactory) securityContextFactory)
+			securityToken = ((org.apache.taverna.server.master.worker.SecurityContextFactory) securityContextFactory)
 					.issueNewPassword();
 		}
 		// Properties that are set multiple times

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDBSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDBSupport.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDBSupport.java
index 5fa96b8..9cbe5b4 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDBSupport.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDBSupport.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@ import java.util.List;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.taverna.server.master.notification.NotificationEngine;
+import org.apache.taverna.server.master.notification.NotificationEngine;
 
 /**
  * The interface to the database of runs.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabase.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabase.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabase.java
index 65aec70..b9470a2 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabase.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabase.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -36,15 +36,15 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.notification.NotificationEngine;
-import org.taverna.server.master.notification.NotificationEngine.Message;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.Policy;
+import org.apache.taverna.server.master.interfaces.RunStore;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.notification.NotificationEngine;
+import org.apache.taverna.server.master.notification.NotificationEngine.Message;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * The main facade bean that interfaces to the database of runs.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabaseDAO.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabaseDAO.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabaseDAO.java
index 1c75d22..c7e0de6 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabaseDAO.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabaseDAO.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.worker;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.worker.RunConnection.toDBform;
+import static org.apache.taverna.server.master.worker.RunConnection.toDBform;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -35,11 +35,11 @@ import javax.jdo.annotations.PersistenceAware;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.JDOSupport;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.interfaces.Policy;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.JDOSupport;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * This handles storing runs, interfacing with the underlying state engine as

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunFactoryConfiguration.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunFactoryConfiguration.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunFactoryConfiguration.java
index 642a6d6..c60bc94 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunFactoryConfiguration.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunFactoryConfiguration.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.worker;
 
 import static org.springframework.jmx.support.MetricType.COUNTER;
 import static org.springframework.jmx.support.MetricType.GAUGE;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.apache.taverna.server.master.TavernaServer.JMX_ROOT;
 
 import java.util.List;
 
@@ -33,8 +33,8 @@ import org.springframework.core.annotation.Order;
 import org.springframework.jmx.export.annotation.ManagedAttribute;
 import org.springframework.jmx.export.annotation.ManagedMetric;
 import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.localworker.LocalWorkerState;
+import org.apache.taverna.server.master.factories.ConfigurableRunFactory;
+import org.apache.taverna.server.master.localworker.LocalWorkerState;
 
 @ManagedResource(objectName = JMX_ROOT + "Factory", description = "The factory for runs.")
 public abstract class RunFactoryConfiguration implements ConfigurableRunFactory {
@@ -386,7 +386,7 @@ public abstract class RunFactoryConfiguration implements ConfigurableRunFactory
 
 	/**
 	 * @return A count of the number of runs believed to actually be in the
-	 *         {@linkplain uk.org.taverna.server.master.common.Status#Operating
+	 *         {@linkplain uk.org.apache.taverna.server.master.common.Status#Operating
 	 *         operating} state.
 	 * @throws Exception
 	 *             If anything goes wrong.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegate.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegate.java
index bb76f85..e331d3f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegate.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegate.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,10 +21,10 @@ package org.taverna.server.master.worker;
 import static java.lang.String.format;
 import static java.util.Arrays.fill;
 import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.defaults.Default.CERTIFICATE_FIELD_NAMES;
-import static org.taverna.server.master.defaults.Default.CERTIFICATE_TYPE;
-import static org.taverna.server.master.defaults.Default.CREDENTIAL_FILE_SIZE_LIMIT;
-import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
+import static org.apache.taverna.server.master.defaults.Default.CERTIFICATE_FIELD_NAMES;
+import static org.apache.taverna.server.master.defaults.Default.CERTIFICATE_TYPE;
+import static org.apache.taverna.server.master.defaults.Default.CREDENTIAL_FILE_SIZE_LIMIT;
+import static org.apache.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -56,16 +56,16 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContext;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteSecurityContext;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.localworker.remote.ImplementationException;
+import org.apache.taverna.server.localworker.remote.RemoteSecurityContext;
+import org.apache.taverna.server.master.common.Credential;
+import org.apache.taverna.server.master.common.Trust;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.InvalidCredentialException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * Implementation of a security context.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegateImpl.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegateImpl.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegateImpl.java
index ef29b55..b413eea 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegateImpl.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegateImpl.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -43,11 +43,11 @@ import javax.xml.ws.handler.MessageContext;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.taverna.server.localworker.remote.RemoteSecurityContext;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.utils.X500Utils;
+import org.apache.taverna.server.localworker.remote.RemoteSecurityContext;
+import org.apache.taverna.server.master.common.Credential;
+import org.apache.taverna.server.master.exceptions.InvalidCredentialException;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.utils.X500Utils;
 
 /**
  * Factoring out of the part of the security context handling that actually

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextFactory.java
index 1d485d8..9bc3634 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextFactory.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -33,12 +33,12 @@ import org.apache.commons.logging.Log;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.springframework.beans.factory.annotation.Required;
 import org.springframework.beans.factory.annotation.Value;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.CertificateChainFetcher;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.utils.X500Utils;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.UriBuilderFactory;
+import org.apache.taverna.server.master.utils.CertificateChainFetcher;
+import org.apache.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.utils.X500Utils;
 
 /**
  * Singleton factory. Really is a singleton (and is also very trivial); the
@@ -49,7 +49,7 @@ import org.taverna.server.master.utils.X500Utils;
  * @author Donal Fellows
  */
 public class SecurityContextFactory implements
-		org.taverna.server.master.interfaces.SecurityContextFactory {
+		org.apache.taverna.server.master.interfaces.SecurityContextFactory {
 	private static final long serialVersionUID = 12345678987654321L;
 	private static SecurityContextFactory instance;
 	transient RunDBSupport db;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
index f9f4d16..69cbfc2 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.worker;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.defaults.Default.NOTIFY_MESSAGE_FORMAT;
+import static org.apache.taverna.server.master.defaults.Default.NOTIFY_MESSAGE_FORMAT;
 
 import java.text.MessageFormat;
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/VelocityCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/VelocityCompletionNotifier.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/VelocityCompletionNotifier.java
index a81e610..d2f7763 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/VelocityCompletionNotifier.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/VelocityCompletionNotifier.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,10 +22,10 @@ import org.apache.velocity.Template;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.apache.taverna.server.master.common.version.Version;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.UriBuilderFactory;
 
 public class VelocityCompletionNotifier implements CompletionNotifier {
 	private String subject;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/WorkerModel.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/WorkerModel.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/WorkerModel.java
index 510c8d0..21b4635 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/WorkerModel.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/WorkerModel.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,7 +21,7 @@ package org.taverna.server.master.worker;
 import java.net.URI;
 import java.util.List;
 
-import org.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Status;
 
 /**
  * Profile of the getters and setters in a worker system. Ensures that the

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/package-info.java
index e96b794..b4fd58a 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/package-info.java
@@ -3,7 +3,7 @@
 /**
  * A Taverna Server back-end that works by forking off workflow executors.
  */
-package org.taverna.server.master.worker;
+package org.apache.taverna.server.master.worker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/webapp/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/META-INF/persistence.xml b/taverna-server-webapp/src/main/webapp/META-INF/persistence.xml
index ced0a39..19d2f15 100644
--- a/taverna-server-webapp/src/main/webapp/META-INF/persistence.xml
+++ b/taverna-server-webapp/src/main/webapp/META-INF/persistence.xml
@@ -19,12 +19,12 @@ limitations under the License.
 	xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd ">
 	<persistence-unit name="TavernaServer">
-		<class>org.taverna.server.master.WebappState</class>
-		<class>org.taverna.server.master.identity.User</class>
-		<class>org.taverna.server.master.localworker.PersistedState</class>
-		<class>org.taverna.server.master.notification.atom.Event</class>
-		<class>org.taverna.server.master.usage.UsageRecord</class>
-		<class>org.taverna.server.master.worker.RunConnection</class>
+		<class>org.apache.taverna.server.master.WebappState</class>
+		<class>org.apache.taverna.server.master.identity.User</class>
+		<class>org.apache.taverna.server.master.localworker.PersistedState</class>
+		<class>org.apache.taverna.server.master.notification.atom.Event</class>
+		<class>org.apache.taverna.server.master.usage.UsageRecord</class>
+		<class>org.apache.taverna.server.master.worker.RunConnection</class>
 		<exclude-unlisted-classes>true</exclude-unlisted-classes>
 	</persistence-unit>
 </persistence>


[23/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/TavernaServerSOAP.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/TavernaServerSOAP.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/TavernaServerSOAP.java
new file mode 100644
index 0000000..f41539c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/TavernaServerSOAP.java
@@ -0,0 +1,1566 @@
+/*
+ */
+package org.taverna.server.master.soap;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Roles.USER;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.security.RolesAllowed;
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.jws.WebService;
+import javax.xml.bind.annotation.XmlElement;
+
+import org.apache.cxf.annotations.WSDLDocumentation;
+import org.apache.taverna.server.usagerecord.JobUsageRecord;
+import org.taverna.server.master.common.Capability;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.DirEntryReference;
+import org.taverna.server.master.common.InputDescription;
+import org.taverna.server.master.common.Permission;
+import org.taverna.server.master.common.ProfileList;
+import org.taverna.server.master.common.RunReference;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.common.version.Version;
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoCredentialException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.exceptions.NotOwnerException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.rest.TavernaServerREST;
+import org.taverna.server.port_description.OutputDescription;
+
+/**
+ * The SOAP service interface to Taverna 3 Server.
+ * 
+ * @author Donal Fellows
+ * @see TavernaServerREST
+ */
+@RolesAllowed(USER)
+@WebService(name = "tavernaService", targetNamespace = SERVER_SOAP)
+@WSDLDocumentation("The SOAP service interface to Taverna " + Version.JAVA
+		+ " Server.")
+public interface TavernaServerSOAP {
+	/**
+	 * Make a run for a particular workflow.
+	 * 
+	 * @param workflow
+	 *            The workflow to instantiate.
+	 * @return Annotated handle for created run.
+	 * @throws NoUpdateException
+	 * @throws NoCreateException
+	 */
+	@WebResult(name = "Run")
+	@WSDLDocumentation("Make a run for a particular workflow.")
+	RunReference submitWorkflow(
+			@WebParam(name = "workflow") @XmlElement(required = true) Workflow workflow)
+					throws NoUpdateException, NoCreateException;
+
+	/**
+	 * Make a run for a particular workflow.
+	 * 
+	 * @param workflow
+	 *            The workflow to instantiate.
+	 * @return Annotated handle for created run.
+	 * @throws NoUpdateException
+	 * @throws NoCreateException
+	 */
+	@WebResult(name = "Run")
+	@WSDLDocumentation("Make a run for a particular workflow.")
+	RunReference submitWorkflowMTOM(
+			@WebParam(name = "workflow") @XmlElement(required = true) WrappedWorkflow workflow)
+			throws NoUpdateException;
+
+	/**
+	 * Make a run for a particular workflow, where that workflow will be
+	 * downloaded from elsewhere. The URI <i>must</i> be publicly readable.
+	 * 
+	 * @param workflowURI
+	 *            The URI to the workflow to instantiate.
+	 * @return Annotated handle for created run.
+	 * @throws NoUpdateException
+	 * @throws NoCreateException
+	 */
+	@WebResult(name = "Run")
+	@WSDLDocumentation("Make a run for a particular workflow where that "
+			+ "workflow is given by publicly readable URI.")
+	RunReference submitWorkflowByURI(
+			@WebParam(name = "workflowURI") @XmlElement(required = true) URI workflowURI)
+			throws NoCreateException, NoUpdateException;
+
+	/**
+	 * Get the list of existing runs owned by the user.
+	 * 
+	 * @return Annotated handle list.
+	 */
+	@WebResult(name = "Run")
+	@WSDLDocumentation("Get the list of existing runs owned by the user.")
+	RunReference[] listRuns();
+
+	/**
+	 * Get the upper limit on the number of runs that the user may create at
+	 * once.
+	 * 
+	 * @return The limit. <b>NB:</b> the number currently operating may be
+	 *         larger, but in that case no further runs can be made until some
+	 *         of the old ones are destroyed.
+	 */
+	@WebResult(name = "MaxSimultaneousRuns")
+	@WSDLDocumentation("Get the upper limit on the number of runs that the user may create at once.")
+	int getServerMaxRuns();
+
+	/**
+	 * Get the list of allowed workflows. If the list is empty, <i>any</i>
+	 * workflow may be used.
+	 * 
+	 * @return A list of workflow documents.
+	 */
+	@WebMethod(operationName = "getPermittedWorkflowURIs")
+	@WebResult(name = "PermittedWorkflowURI")
+	@WSDLDocumentation("Get the list of URIs to allowed workflows. If the list is empty, any workflow may be used including those not submitted via URI.")
+	URI[] getServerWorkflows();
+
+	/**
+	 * Get the list of allowed event listeners.
+	 * 
+	 * @return A list of listener names.
+	 */
+	@WebMethod(operationName = "getPermittedListenerTypes")
+	@WebResult(name = "PermittedListenerType")
+	@WSDLDocumentation("Get the list of allowed types of event listeners.")
+	String[] getServerListeners();
+
+	/**
+	 * Get the list of notification fabrics.
+	 * 
+	 * @return A list of listener names.
+	 */
+	@WebMethod(operationName = "getEnabledNotificationFabrics")
+	@WebResult(name = "EnabledNotifierFabric")
+	@WSDLDocumentation("Get the list of notification fabrics. Each is a URI scheme.")
+	String[] getServerNotifiers();
+
+	@WebMethod(operationName = "getCapabilities")
+	@WebResult(name = "Capabilities")
+	@WSDLDocumentation("Get the workflow execution capabilities of this "
+			+ "Taverna Server instance.")
+	List<Capability> getServerCapabilities();
+
+	/**
+	 * Destroy a run immediately. This might or might not actually relinquish
+	 * resources; that's up to the service implementation and deployment.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the lifetime of the
+	 *             run.
+	 */
+	@WSDLDocumentation("Destroy a run immediately.")
+	void destroyRun(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, NoUpdateException;
+
+	/**
+	 * Get the workflow document used to create the given run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The workflow document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "CreationWorkflow")
+	@WSDLDocumentation("Get the workflow document used to create the given run.")
+	Workflow getRunWorkflow(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the workflow document used to create the given run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The workflow document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "CreationWorkflow")
+	@WSDLDocumentation("Get the workflow document used to create the given run.")
+	WrappedWorkflow getRunWorkflowMTOM(
+			@WebParam(name = "runName") String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get a description of the profiles supported by the workflow document used
+	 * to create the given run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return A description of the supported profiles.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Profiles")
+	@WSDLDocumentation("Get a description of the profiles supported by the workflow document used to create the given run.")
+	ProfileList getRunWorkflowProfiles(
+			@WebParam(name = "runName") String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the descriptive name of the workflow run. The descriptive name
+	 * carries no deep information.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The descriptive name of the run.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "DescriptiveName")
+	@WSDLDocumentation("Get the descriptive name of the workflow run. Carries no deep information.")
+	String getRunDescriptiveName(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Set the descriptive name of the workflow run. The descriptive name
+	 * carries no deep information.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param descriptiveName
+	 *            The new descriptive name to set. Note that the implementation
+	 *            is allowed to arbitrarily truncate this value.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not permitted to update this run.
+	 */
+	@WSDLDocumentation("Set the descriptive name of the workflow run. Carries no deep information.")
+	void setRunDescriptiveName(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "descriptiveName") @XmlElement(required = true) String descriptiveName)
+			throws UnknownRunException, NoUpdateException;
+
+	/**
+	 * Get the description of the inputs to the workflow run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The input description
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "RunInputDescription")
+	@WSDLDocumentation("Get the description of the inputs currently set up for the given workflow run.")
+	InputDescription getRunInputs(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get a description of what inputs the workflow run <i>expects</i> to
+	 * receive.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The description document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "RunInputDescriptor")
+	@WSDLDocumentation("Get a description of what inputs the given workflow run expects to receive.")
+	org.taverna.server.port_description.InputDescription getRunInputDescriptor(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Tells the run to use the given Baclava file for all inputs.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param fileName
+	 *            The name of the file to use. Must not start with a <tt>/</tt>
+	 *            or contain a <tt>..</tt> element.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws FilesystemAccessException
+	 *             If the filename is illegal.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state
+	 */
+	@WSDLDocumentation("Tells the given run to use the given already-uploaded Baclava file for all inputs.")
+	void setRunInputBaclavaFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "baclavaFileName") String fileName)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, BadStateChangeException;
+
+	/**
+	 * Tells the run to use the given file for input on the given port. This
+	 * overrides any previously set file or value on the port and causes the
+	 * server to forget about using a Baclava file for all inputs.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param portName
+	 *            The port to use the file for.
+	 * @param portFilename
+	 *            The file to use on the port. Must not start with a <tt>/</tt>
+	 *            or contain a <tt>..</tt> element.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws FilesystemAccessException
+	 *             If the filename is illegal.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 * @throws BadPropertyValueException
+	 *             If the input port may not be changed to the contents of the
+	 *             given file.
+	 */
+	@WSDLDocumentation("Tells the given run to use the given file for input on the given port.")
+	void setRunInputPortFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "portName") @XmlElement(required = true) String portName,
+			@WebParam(name = "portFileName") @XmlElement(required = true) String portFilename)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, BadStateChangeException,
+			BadPropertyValueException;
+
+	/**
+	 * Tells the run to use the given value for input on the given port. This
+	 * overrides any previously set file or value on the port and causes the
+	 * server to forget about using a Baclava file for all inputs. Note that
+	 * this is wholly unsuitable for use with binary data.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param portName
+	 *            The port to use the file for.
+	 * @param portValue
+	 *            The literal value to use on the port.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 * @throws BadPropertyValueException
+	 *             If the input port may not be changed to the given literal
+	 *             value.
+	 */
+	@WSDLDocumentation("Tells the given run to use the given literal string value for input on the given port.")
+	void setRunInputPortValue(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "portName") @XmlElement(required = true) String portName,
+			@WebParam(name = "portValue") @XmlElement(required = true) String portValue)
+			throws UnknownRunException, NoUpdateException,
+			BadStateChangeException, BadPropertyValueException;
+
+	/**
+	 * Tells the given run to use the given list delimiter (a single-character
+	 * string value) for splitting the input on the given port. Note that
+	 * nullability of the delimiter is supported here.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param portName
+	 *            The port to set the list delimiter for.
+	 * @param delimiter
+	 *            The single-character value (in range U+00001..U+0007F) to use
+	 *            as the delimiter, or <tt>null</tt> for no delimiter at all.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 * @throws BadPropertyValueException
+	 *             If the delimiter may not be changed to the given literal
+	 *             value.
+	 */
+	@WSDLDocumentation("Tells the given run to use the given list delimiter (a single-character string value) for splitting the input on the given port. Note that nullability of the delimiter is supported here.")
+	void setRunInputPortListDelimiter(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "portName") @XmlElement(required = true) String portName,
+			@WebParam(name = "delimiter") String delimiter)
+			throws UnknownRunException, NoUpdateException,
+			BadStateChangeException, BadPropertyValueException;
+
+	/**
+	 * Get the Baclava file where the output of the run will be written.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The filename, or <tt>null</tt> if the results will be written to
+	 *         a subdirectory <tt>out</tt> of the run's working directory.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "OutputBaclavaFile")
+	@WSDLDocumentation("Get the Baclava file where the output of the run will be written.")
+	String getRunOutputBaclavaFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Set the Baclava file where the output of the run will be written.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param outputFile
+	 *            The filename for the Baclava file, or <tt>null</tt> or the
+	 *            empty string to indicate that the results are to be written to
+	 *            the subdirectory <tt>out</tt> of the run's working directory.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws FilesystemAccessException
+	 *             If the filename is illegal (starts with a <tt>/</tt> or
+	 *             contains a <tt>..</tt> element.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state
+	 */
+	@WSDLDocumentation("Set the Baclava file where the output of the run will be written.")
+	void setRunOutputBaclavaFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "baclavaFileName") String outputFile)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, BadStateChangeException;
+
+	/**
+	 * Return a description of the outputs of a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Description document (higher level than filesystem traverse).
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws BadStateChangeException
+	 *             If the run is in the {@link Status#Initialized Initialized}
+	 *             state
+	 * @throws FilesystemAccessException
+	 *             If there is an exception when accessing the filesystem.
+	 * @throws NoDirectoryEntryException
+	 *             If things are odd in the filesystem.
+	 */
+	@WebResult(name = "OutputDescription")
+	@WSDLDocumentation("Return a description of the outputs of a run. Only known during/after the run.")
+	OutputDescription getRunOutputDescription(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, BadStateChangeException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Get the time when the run will be eligible to be automatically deleted.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return A date at which the expiry will be scheduled. The actual deletion
+	 *         will happen an arbitrary amount of time later (depending on
+	 *         system policy).
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Expiry")
+	@WSDLDocumentation("Get the time when the run will be eligible to be automatically deleted.")
+	Date getRunExpiry(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Set when the run will be eligible to be automatically deleted.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param expiry
+	 *            A date at which the expiry will be scheduled. The actual
+	 *            deletion will happen an arbitrary amount of time later
+	 *            (depending on system policy).
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the lifetime of the
+	 *             run.
+	 */
+	@WSDLDocumentation("Set when the run will be eligible to be automatically deleted.")
+	void setRunExpiry(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "expiry") @XmlElement(required = true) Date expiry)
+			throws UnknownRunException, NoUpdateException;
+
+	/**
+	 * Get the time when the run was created.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The moment when the run was created (modulo some internal
+	 *         overhead).
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "CreationTime")
+	@WSDLDocumentation("Get the time when the run was created.")
+	Date getRunCreationTime(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the time when the run was started.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The moment when the run was started (modulo some internal
+	 *         overhead) or <tt>null</tt> to indicate that it has never started.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "StartTime")
+	@WSDLDocumentation("Get the time when the run was started.")
+	Date getRunStartTime(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the time when the run was detected as having finished.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The moment when the run was believed stopped. Note that this may
+	 *         not be when the run <i>actually</i> finished; promptness of
+	 *         detection depends on many factors.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "FinishTime")
+	@WSDLDocumentation("Get the time when the run was detected as having finished.")
+	Date getRunFinishTime(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the current status of the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The status code.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Status")
+	@WSDLDocumentation("Get the current status of the given workflow run.")
+	Status getRunStatus(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Set the status of a run. This is used to start it executing, make it stop
+	 * executing, etc. Note that changing the status of a run can <i>never</i>
+	 * cause the run to be destroyed.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param status
+	 *            The status to change to. Changing to the current status will
+	 *            always have no effect.
+	 * @return An empty string if the state change was completed, or a
+	 *         description (never empty) of why the state change is ongoing.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws BadStateChangeException
+	 *             If the state change requested is impossible.
+	 */
+	@WebResult(name = "PartialityReason")
+	@WSDLDocumentation("Set the status of a given workflow run.")
+	String setRunStatus(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "status") @XmlElement(required = true) Status status)
+			throws UnknownRunException, NoUpdateException,
+			BadStateChangeException;
+
+	/**
+	 * Get the names of the event listeners attached to the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The listener names.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "ListenerName")
+	@WSDLDocumentation("Get the names of the event listeners attached to the run.")
+	String[] getRunListeners(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Adds an event listener to the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerType
+	 *            The type of event listener to add. Must be one of the names
+	 *            returned by the {@link #getServerListeners()} operation.
+	 * @param configuration
+	 *            The configuration document for the event listener; the
+	 *            interpretation of the configuration is up to the listener.
+	 * @return The actual name of the listener.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws NoListenerException
+	 *             If the listener construction fails (<i>e.g.</i>, due to an
+	 *             unsupported <b>listenerType</b> or a problem with the
+	 *             <b>configuration</b>).
+	 */
+	@WebResult(name = "ListenerName")
+	@WSDLDocumentation("Adds an event listener to the run.")
+	String addRunListener(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerType") @XmlElement(required = true) String listenerType,
+			@WebParam(name = "configuration") @XmlElement(required = true) String configuration)
+			throws UnknownRunException, NoUpdateException, NoListenerException;
+
+	/**
+	 * Returns the standard output of the workflow run. Unstarted runs return
+	 * the empty string.
+	 * <p>
+	 * The equivalent thing can also be fetched from the relevant listener
+	 * property (i.e., io/stdout).
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Whatever the run engine printed on its stdout.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "StandardOutput")
+	@WSDLDocumentation("Returns the stdout from the run engine.")
+	String getRunStdout(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Returns the standard error of the workflow run. Unstarted runs return the
+	 * empty string.
+	 * <p>
+	 * The equivalent thing can also be fetched from the relevant listener
+	 * property (i.e., io/stderr).
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Whatever the run engine printed on its stderr.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "StandardError")
+	@WSDLDocumentation("Returns the stderr from the run engine.")
+	String getRunStderr(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Returns the usage record for the workflow run. Unfinished runs return
+	 * <tt>null</tt>.
+	 * <p>
+	 * The equivalent thing can also be fetched from the relevant listener
+	 * property (i.e., io/usage).
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The usage record, or <tt>null</tt>.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "ResourceUsage")
+	@WSDLDocumentation("Returns the resource usage from the run engine.")
+	JobUsageRecord getRunUsageRecord(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Returns the log of the workflow run. Unstarted runs return the empty
+	 * string.
+	 * <p>
+	 * This can also be fetched from the appropriate file (i.e.,
+	 * <tt>logs/detail.log</tt>).
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Whatever the run engine wrote to its log.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Log")
+	@WSDLDocumentation("Returns the detailed log from the run engine.")
+	String getRunLog(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Returns the run bundle of a run. The run must be <i>finished</i> for this
+	 * to be guaranteed to be present, and must <i>not</i> have had its output
+	 * generated as Baclava.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The contents of the run bundle.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If there was a problem reading the bundle.
+	 * @throws NoDirectoryEntryException
+	 *             If the bundle doesn't exist currently.
+	 */
+	@WebResult(name = "RunBundle")
+	@WSDLDocumentation("Gets the run bundle of a finished run. MTOM support recommended!")
+	FileContents getRunBundle(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Gets whether to generate provenance (in a run bundle) for a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Whether provenance will be generated.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "GenerateProvenance")
+	@WSDLDocumentation("Gets whether a run generates provenance.")
+	boolean getRunGenerateProvenance(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Sets whether to generate provenance (in a run bundle) for a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param generateProvenance
+	 *            Whether to generate provenance.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to manipulate the run.
+	 */
+	@WSDLDocumentation("Sets whether a run generates provenance. "
+			+ "Only usefully settable before the run is started.")
+	void setRunGenerateProvenance(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "generateProvenance") @XmlElement(required = true) boolean generateProvenance)
+			throws UnknownRunException, NoUpdateException;
+
+	/**
+	 * Get the owner of the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The status code.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Owner")
+	@WSDLDocumentation("Get the owner of the given workflow run.")
+	String getRunOwner(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the list of permissions associated with a workflow run.
+	 * 
+	 * @param runName
+	 *            The name of the run whose permissions are to be obtained.
+	 * @return A description of the non-<tt>none</tt> permissions.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the current
+	 *             user is not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If asked to provide this information about a run that the
+	 *             current user may see but where they are not the owner of it.
+	 */
+	@WebResult(name = "PermissionList")
+	@WSDLDocumentation("Get the list of permissions associated with a given workflow run.")
+	PermissionList listRunPermissions(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, NotOwnerException;
+
+	/**
+	 * Set the permission for a user to access and update a particular workflow
+	 * run.
+	 * 
+	 * @param runName
+	 *            The name of the run whose permissions are to be updated.
+	 * @param userName
+	 *            The name of the user about whom this call is talking.
+	 * @param permission
+	 *            The permission level to set.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the current
+	 *             user is not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If asked to provide this information about a run that the
+	 *             current user may see but where they are not the owner of it.
+	 */
+	@WSDLDocumentation("Set the permission for a user to access and update a given workflow run.")
+	void setRunPermission(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "userName") @XmlElement(required = true) String userName,
+			@WebParam(name = "permission") @XmlElement(required = true) Permission permission)
+			throws UnknownRunException, NotOwnerException;
+
+	/**
+	 * Get the credentials associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The collection of credentials.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may see the credentials.
+	 */
+	@WebResult(name = "Credentials")
+	@WSDLDocumentation("Get the credentials (passwords, private keys) associated with the given workflow run. Only the owner may do this.")
+	Credential[] getRunCredentials(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, NotOwnerException;
+
+	/**
+	 * Set a credential associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param credentialID
+	 *            The handle of the credential to set. If empty, a new
+	 *            credential will be created.
+	 * @param credential
+	 *            The credential to set.
+	 * @return The handle of the credential that was created or updated.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may manipulate the credentials.
+	 * @throws InvalidCredentialException
+	 *             If the <b>credential</b> fails its checks.
+	 * @throws NoCredentialException
+	 *             If the <b>credentialID</b> is not empty but does not
+	 *             correspond to an existing credential.
+	 * @throws BadStateChangeException
+	 *             If an attempt to manipulate the credentials is done after the
+	 *             workflow has started running.
+	 */
+	@WebResult(name = "credentialID")
+	@WSDLDocumentation("Set a credential (password, private key, etc.) associated with the given run. Only the owner may do this.")
+	String setRunCredential(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "credentialID") @XmlElement(required = true) String credentialID,
+			@WebParam(name = "credential") @XmlElement(required = true) Credential credential)
+			throws UnknownRunException, NotOwnerException,
+			InvalidCredentialException, NoCredentialException,
+			BadStateChangeException;
+
+	/**
+	 * Delete a credential associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param credentialID
+	 *            The handle of the credential to delete. If empty, a new
+	 *            credential will be created.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may manipulate the credentials.
+	 * @throws NoCredentialException
+	 *             If the given credentialID does not exist.
+	 * @throws BadStateChangeException
+	 *             If an attempt to manipulate the credentials is done after the
+	 *             workflow has started running.
+	 */
+	@WSDLDocumentation("Delete a credential associated with the given run. Only the owner may do this.")
+	void deleteRunCredential(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "credentialID") @XmlElement(required = true) String credentialID)
+			throws UnknownRunException, NotOwnerException,
+			NoCredentialException, BadStateChangeException;
+
+	/**
+	 * Get the certificate collections associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The collection of credentials.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may see the credentials.
+	 */
+	@WebResult(name = "CertificateCollections")
+	@WSDLDocumentation("Get the trusted (server or CA) certificates associated with the run. Only the owner may do this.")
+	Trust[] getRunCertificates(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, NotOwnerException;
+
+	/**
+	 * Set a certificate collection associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param certificateID
+	 *            The handle of the certificate collection to set. If empty, a
+	 *            new certificate collection will be created.
+	 * @param certificate
+	 *            The certificate collection to set.
+	 * @return The handle of the certificate set that was created or updated.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may manipulate the certificates.
+	 * @throws InvalidCredentialException
+	 *             If the <b>certificate</b> fails its checks.
+	 * @throws NoCredentialException
+	 *             If the <b>credentialID</b> is not empty but does not
+	 *             correspond to an existing certificate collection.
+	 * @throws BadStateChangeException
+	 *             If an attempt to manipulate the credentials is done after the
+	 *             workflow has started running.
+	 */
+	@WebResult(name = "certificateID")
+	@WSDLDocumentation("Set a trusted (server or CA) certificate associated with the run. Only the owner may do this.")
+	String setRunCertificates(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "certificateID") String certificateID,
+			@WebParam(name = "certificate") @XmlElement(required = true) Trust certificate)
+			throws UnknownRunException, NotOwnerException,
+			InvalidCredentialException, NoCredentialException,
+			BadStateChangeException;
+
+	/**
+	 * Delete a certificate collection associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param certificateID
+	 *            The handle of the credential to delete.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may manipulate the certificates.
+	 * @throws NoCredentialException
+	 *             If the given certificateID does not exist.
+	 * @throws BadStateChangeException
+	 *             If an attempt to manipulate the credentials is done after the
+	 *             workflow has started running.
+	 */
+	@WSDLDocumentation("Delete a trusted (server or CA) certificate associated with the run. Only the owner may do this.")
+	void deleteRunCertificates(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "certificateID") @XmlElement(required = true) String certificateID)
+			throws UnknownRunException, NotOwnerException,
+			NoCredentialException, BadStateChangeException;
+
+	/**
+	 * Get the contents of any directory at/under the run's working directory.
+	 * Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param directory
+	 *            The name of the directory to fetch; the main working directory
+	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return A list of entries. They are assumed to be all directories or
+	 *         files.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a file).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the directory can't be looked up.
+	 */
+	@WebResult(name = "DirectoryEntry")
+	@WSDLDocumentation("Get the contents of any directory at/under the run's working directory.")
+	DirEntry[] getRunDirectoryContents(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the contents of any directory (and its subdirectories) at/under the
+	 * run's working directory, returning it as a compressed ZIP file. Runs do
+	 * not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param directory
+	 *            The name of the directory to fetch; the main working directory
+	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return A serialized ZIP file.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a file).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the directory can't be looked up.
+	 */
+	@WebResult(name = "ZipFile")
+	@WSDLDocumentation("Get the contents of any directory (and its subdirectories) at/under the run's working directory, returning it as a compressed ZIP file.")
+	byte[] getRunDirectoryAsZip(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the contents of any directory (and its subdirectories) at/under the
+	 * run's working directory, returning it as a compressed ZIP file that is
+	 * streamed via MTOM. Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param directory
+	 *            The name of the directory to fetch; the main working directory
+	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return An MTOM-streamable ZIP file reference.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a file).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the directory can't be looked up.
+	 */
+	@WebResult(name = "ZipStream")
+	@WSDLDocumentation("Get the contents of any directory (and its subdirectories) at/under the run's working directory, returning it as a compressed ZIP file that is streamed by MTOM.")
+	ZippedDirectory getRunDirectoryAsZipMTOM(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Make a new empty directory beneath an existing one, which must be the
+	 * run's working directory or a directory beneath it. Runs do not share
+	 * working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param parent
+	 *            The parent directory that will have the new directory added
+	 *            beneath it.
+	 * @param name
+	 *            The name of the directory to create. Must not be the same as
+	 *            any other file or directory in the <i>parent</i> directory.
+	 *            The name <i>must not</i> consist of <tt>..</tt> or have a
+	 *            <tt>/</tt> in it.
+	 * @return A reference to the created directory.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., making something with
+	 *             the same name as something that already exists).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the containing directory can't be looked up.
+	 */
+	@WebResult(name = "CreatedDirectory")
+	@WSDLDocumentation("Make a new empty directory beneath an existing one, all relative to the given run's main working directory.")
+	DirEntry makeRunDirectory(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "parentDirectory") @XmlElement(required = true) DirEntry parent,
+			@WebParam(name = "directoryName") @XmlElement(required = true) String name)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Make a new empty file in an existing directory, which may be the run's
+	 * working directory or any directory beneath it. Runs do not share working
+	 * directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param parent
+	 *            The parent directory that will have the new file added to it.
+	 * @param name
+	 *            The name of the file to create. Must not be the same as any
+	 *            other file or directory in the <i>parent</i> directory. The
+	 *            name <i>must not</i> consist of <tt>..</tt> or have a
+	 *            <tt>/</tt> in it.
+	 * @return A reference to the created file. The file will be empty.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., making something with
+	 *             the same name as something that already exists).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the containing directory can't be looked up.
+	 */
+	@WebResult(name = "CreatedFile")
+	@WSDLDocumentation("Make a new empty file in an existing directory, which may be the run's working directory or any directory beneath it.")
+	DirEntry makeRunFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "parentDirectory") @XmlElement(required = true) DirEntry parent,
+			@WebParam(name = "fileNameTail") @XmlElement(required = true) String name)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Destroy an entry (file or directory) in or beneath a run's working
+	 * directory. Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param dirEntry
+	 *            Reference to an existing item in a directory that will be
+	 *            destroyed. May be a reference to either a file or a directory.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., deleting something
+	 *             which doesn't exist or attempting to delete the main working
+	 *             directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the file or directory can't be looked up.
+	 */
+	@WSDLDocumentation("Destroy an entry (file or directory) in or beneath a run's working directory.")
+	void destroyRunDirectoryEntry(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "directoryEntry") @XmlElement(required = true) DirEntry dirEntry)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Get the contents of a file under the run's working directory. Runs do not
+	 * share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to fetch; the main working directory is
+	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return The literal byte contents of the file.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WebResult(name = "FileContents")
+	@WSDLDocumentation("Get the contents of a file under the run's working directory.")
+	byte[] getRunFileContents(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the contents of a file under the run's working directory via MTOM.
+	 * Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to fetch; the main working directory is
+	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return The contents, described for transfer via MTOM.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WebResult(name = "FileContentsMTOM")
+	@WSDLDocumentation("Get the contents of a file via MTOM.")
+	FileContents getRunFileContentsMTOM(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Set the contents of a file under the run's working directory. Runs do not
+	 * share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to update; the main working directory is
+	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @param newContents
+	 *            The literal bytes to set the file contents to.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., writing the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WSDLDocumentation("Set the contents of a file under the run's working directory.")
+	void setRunFileContents(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file,
+			@WebParam(name = "contents") @XmlElement(required = true) byte[] newContents)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Set the contents of a file under the run's working directory. Runs do not
+	 * share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param newContents
+	 *            The description of what file to set, and what to the file
+	 *            contents should be set to.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., writing the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WSDLDocumentation("Set the contents of a file under the run's working directory.")
+	void setRunFileContentsMTOM(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "contents") @XmlElement(required = true) FileContents newContents)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Set the contents of a file under the run's working directory to the
+	 * contents of a publicly readable URI. Runs do not share working
+	 * directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to update; the main working directory is
+	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @param reference
+	 *            The publicly readable URI whose contents are to become the
+	 *            literal bytes of the file's contents.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., writing the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WSDLDocumentation("Set the contents of a file under the run's working directory from the contents of a publicly readable URI.")
+	void setRunFileContentsFromURI(@WebParam(name = "runName") String runName,
+			@WebParam(name = "fileName") DirEntryReference file,
+			@WebParam(name = "contents") URI reference)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Get the length of any file (in bytes) at/under the run's working
+	 * directory. Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to get the length of; the main working
+	 *            directory is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return The number of bytes in the file.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the length of a
+	 *             directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WebResult(name = "FileLength")
+	@WSDLDocumentation("Get the length of any file (in bytes) at/under the run's working directory.")
+	long getRunFileLength(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the time that the file or directory (at/under the run's working
+	 * directory) was last modified. Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to get the modification date of; the main
+	 *            working directory is <tt>/</tt> and <tt>..</tt> is always
+	 *            disallowed.
+	 * @return The modification date of the file or directory, as understood by
+	 *         the underlying operating system.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated.
+	 * @throws NoDirectoryEntryException
+	 *             If the file or directory doesn't exist.
+	 */
+	@WebResult(name = "FileModified")
+	@WSDLDocumentation("Get the length of any file (in bytes) at/under the run's working directory.")
+	Date getRunFileModified(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the content type of any file at/under the run's working directory.
+	 * Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to get the length of; the main working
+	 *            directory is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return The content type of the file.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the length of a
+	 *             directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WebResult(name = "FileContentType")
+	@WSDLDocumentation("Get the content type of any file at/under the run's working directory.")
+	String getRunFileType(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the configuration document for an event listener attached to a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerName
+	 *            The name of the listener attached.
+	 * @return The configuration document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoListenerException
+	 *             If no such listener exists.
+	 */
+	@WebResult(name = "ListenerConfiguration")
+	@WSDLDocumentation("Get the configuration document for an event listener attached to a run.")
+	String getRunListenerConfiguration(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName)
+			throws UnknownRunException, NoListenerException;
+
+	/**
+	 * Get the list of properties supported by an event listener attached to a
+	 * run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerName
+	 *            The name of the listener attached.
+	 * @return The list of property names.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoListenerException
+	 *             If no such listener exists.
+	 */
+	@WebResult(name = "ListenerPropertyName")
+	@WSDLDocumentation("Get the list of properties supported by an event listener attached to a run.")
+	String[] getRunListenerProperties(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName)
+			throws UnknownRunException, NoListenerException;
+
+	/**
+	 * Get the value of a property for an event listener attached to a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerName
+	 *            The name of the listener attached.
+	 * @param propertyName
+	 *            The name of the property to read.
+	 * @return The configuration document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoListenerException
+	 *             If no such listener exists or if the listener has no such
+	 *             property.
+	 */
+	@WebResult(name = "ListenerPropertyValue")
+	@WSDLDocumentation("Get the value of a property for an event listener attached to a run.")
+	String getRunListenerProperty(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName,
+			@WebParam(name = "propertyName") @XmlElement(required = true) String propertyName)
+			throws UnknownRunException, NoListenerException;
+
+	/**
+	 * Set the value of a property for an event listener attached to a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerName
+	 *            The name of the listener attached.
+	 * @param propertyName
+	 *            The name of the property to write.
+	 * @param value
+	 *            The value to set the property to.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoListenerException
+	 *             If no such listener exists, the listener has no such
+	 *             property, or the value is considered "unacceptable" in some
+	 *             way.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 */
+	@WSDLDocumentation("Set the value of a property for an event listener attached to a run.")
+	void setRunListenerProperty(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName,
+			@WebParam(name = "propertyName") @XmlElement(required = true) String propertyName,
+			@WebParam(name = "propertyValue") @XmlElement(required = true) String value)
+			throws UnknownRunException, NoUpdateException, NoListenerException;
+
+	/**
+	 * Gets the status of the server. Follows the HELIO Monitoring Service
+	 * protocol.
+	 * 
+	 * @return A status string.
+	 */
+	@WSDLDocumentation("A simple way to get the status of the overall server.")
+	@WebResult(name = "ServerStatus")
+	String getServerStatus();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/WrappedWorkflow.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/WrappedWorkflow.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/WrappedWorkflow.java
new file mode 100644
index 0000000..745876d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/WrappedWorkflow.java
@@ -0,0 +1,169 @@
+/*
+ */
+package org.taverna.server.master.soap;
+/*
+ * 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.
+ */
+
+import static javax.xml.bind.annotation.XmlAccessType.NONE;
+import static org.apache.commons.io.IOUtils.closeQuietly;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlMimeType;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.common.Workflow;
+
+import org.apache.taverna.scufl2.api.io.ReaderException;
+import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
+import org.apache.taverna.scufl2.api.io.WriterException;
+
+/**
+ * An MTOM-capable description of how to transfer the contents of a file.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "WorkflowReference")
+@XmlAccessorType(NONE)
+public class WrappedWorkflow {
+	@XmlMimeType("application/octet-stream")
+	// JAXB bug: must be this
+	public DataHandler workflowData;
+	Workflow workflow;
+
+	/**
+	 * Initialize the contents of this descriptor from the given file and
+	 * content type.
+	 * 
+	 * @param workflow
+	 *            The workflow that is to be reported.
+	 */
+	public void setWorkflow(Workflow workflow) {
+		workflowData = new DataHandler(new WorkflowSource(workflow));
+	}
+
+	@XmlTransient
+	public Workflow getWorkflow() throws IOException {
+		if (workflow != null)
+			return workflow;
+		try {
+			return new Workflow(new WorkflowBundleIO().readBundle(
+					workflowData.getInputStream(), null));
+		} catch (ReaderException e) {
+			throw new IOException("problem converting to scufl2 bundle", e);
+		}
+	}
+}
+
+/**
+ * A data source that knows how to deliver a workflow.
+ * 
+ * @author Donal Fellows
+ */
+class WorkflowSource implements DataSource {
+	WorkflowSource(Workflow workflow) {
+		this.wf = workflow;
+		this.io = new WorkflowBundleIO();
+	}
+
+	Workflow wf;
+	final WorkflowBundleIO io;
+
+	@Override
+	public String getContentType() {
+		return wf.getPreferredContentType().getContentType();
+	}
+
+	@Override
+	public String getName() {
+		switch (wf.getPreferredContentType()) {
+		case SCUFL2:
+			return "workflow.scufl2";
+		case T2FLOW:
+			return "workflow.t2flow";
+		default:
+			return "workflow";
+		}
+	}
+
+	@Override
+	public InputStream getInputStream() throws IOException {
+		PipedInputStream is = new PipedInputStream();
+		final OutputStream os = new PipedOutputStream(is);
+		new Worker() {
+			@Override
+			public void doWork() throws WriterException, IOException {
+				io.writeBundle(wf.getScufl2Workflow(), os, wf
+						.getPreferredContentType().getContentType());
+			}
+
+			@Override
+			public void doneWork() {
+				closeQuietly(os);
+			}
+		};
+		return is;
+	}
+
+	@Override
+	public OutputStream getOutputStream() throws IOException {
+		final PipedInputStream is = new PipedInputStream();
+		OutputStream os = new PipedOutputStream(is);
+		new Worker() {
+			@Override
+			public void doWork() throws IOException, ReaderException {
+				wf = new Workflow(io.readBundle(is, null));
+			}
+
+			@Override
+			public void doneWork() {
+				closeQuietly(is);
+			}
+		};
+		return os;
+	}
+
+	static abstract class Worker extends Thread {
+		public Worker() {
+			setDaemon(true);
+			start();
+		}
+
+		public abstract void doWork() throws Exception;
+
+		public abstract void doneWork();
+
+		@Override
+		public void run() {
+			try {
+				doWork();
+			} catch (Exception e) {
+				// do nothing.
+			} finally {
+				doneWork();
+			}
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/ZippedDirectory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/ZippedDirectory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/ZippedDirectory.java
new file mode 100644
index 0000000..5b2d261
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/ZippedDirectory.java
@@ -0,0 +1,102 @@
+/*
+ */
+package org.taverna.server.master.soap;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.activation.UnsupportedDataTypeException;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlMimeType;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.Directory;
+
+/**
+ * An MTOM-capable description of how to transfer the zipped contents of a
+ * directory.
+ * 
+ * @author Donal Fellows
+ * @see Directory#getContentsAsZip()
+ */
+@XmlType(name = "ZippedDirectory")
+public class ZippedDirectory {
+	@XmlElement
+	public String name;
+	@XmlMimeType("application/octet-stream")
+	// JAXB bug: must be this
+	public DataHandler fileData;
+
+	public ZippedDirectory() {
+	}
+
+	/**
+	 * Initialise the contents of this descriptor from the given directory.
+	 * 
+	 * @param dir
+	 *            The directory that is to be reported.
+	 */
+	public ZippedDirectory(Directory dir) {
+		name = dir.getFullName();
+		fileData = new DataHandler(new ZipSource(dir));
+	}
+}
+
+/**
+ * A data source that knows how to communicate with the Taverna Server back-end.
+ * 
+ * @author Donal Fellows
+ */
+class ZipSource implements DataSource {
+	ZipSource(Directory d) {
+		this.d = d;
+	}
+
+	private final Directory d;
+
+	@Override
+	public String getContentType() {
+		return APPLICATION_ZIP_TYPE.toString();
+	}
+
+	@Override
+	public String getName() {
+		return d.getName();
+	}
+
+	@Override
+	public InputStream getInputStream() throws IOException {
+		try {
+			return d.getContentsAsZip();
+		} catch (FilesystemAccessException e) {
+			throw new IOException(e);
+		}
+	}
+
+	@Override
+	public OutputStream getOutputStream() throws IOException {
+		throw new UnsupportedDataTypeException();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/package-info.java
new file mode 100644
index 0000000..cd753b7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/package-info.java
@@ -0,0 +1,44 @@
+/*
+ */
+/**
+ * This package contains the SOAP interface to Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER_SOAP, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "port", namespaceURI = DATA),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.soap;
+/*
+ * 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.
+ */
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.port_description.Namespaces.DATA;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecord.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecord.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecord.java
new file mode 100644
index 0000000..b1f0602
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecord.java
@@ -0,0 +1,130 @@
+/*
+ */
+package org.taverna.server.master.usage;
+/*
+ * 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.
+ */
+
+import java.util.Date;
+
+import javax.jdo.annotations.Column;
+import javax.jdo.annotations.Index;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.PrimaryKey;
+import javax.jdo.annotations.Queries;
+import javax.jdo.annotations.Query;
+import javax.xml.bind.JAXBException;
+
+import org.apache.taverna.server.usagerecord.JobUsageRecord;
+
+/**
+ * A usage record as recorded in the database.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceCapable(table = "USAGE_RECORD_LOG", schema = "UR", cacheable = "true")
+@Queries({ @Query(name = "allByDate", value = "SELECT USAGE_RECORD FROM UR.USAGE_RECORD_LOG ORDER BY CREATE_DATE", resultClass = String.class, unmodifiable = "true", unique = "false", language = "SQL") })
+public class UsageRecord {
+	/**
+	 * Create an empty usage record database entry.
+	 */
+	public UsageRecord() {
+	}
+
+	/**
+	 * Create a usage record database entry that is populated from the given UR.
+	 * 
+	 * @param usageRecord
+	 *            The originating usage record.
+	 * @throws JAXBException
+	 *             If deserialization of the record fails.
+	 */
+	public UsageRecord(String usageRecord) throws JAXBException {
+		JobUsageRecord jur = JobUsageRecord.unmarshal(usageRecord);
+		setUsageRecord(usageRecord);
+		setCreateDate(jur.getRecordIdentity().getCreateTime()
+				.toGregorianCalendar().getTime());
+		setId(jur.getRecordIdentity().getRecordId());
+		setUserid(jur.getUserIdentity().get(0).getLocalUserId());
+	}
+
+	/**
+	 * Create a usage record database entry that is populated from the given UR.
+	 * 
+	 * @param usageRecord
+	 *            The originating usage record.
+	 * @throws JAXBException
+	 *             If serialization of the record fails.
+	 */
+	public UsageRecord(JobUsageRecord usageRecord) throws JAXBException {
+		setUsageRecord(usageRecord.marshal());
+		setCreateDate(usageRecord.getRecordIdentity().getCreateTime()
+				.toGregorianCalendar().getTime());
+		setId(usageRecord.getRecordIdentity().getRecordId());
+		setUserid(usageRecord.getUserIdentity().get(0).getLocalUserId());
+	}
+
+	@PrimaryKey
+	@Column(name = "ID", length = 40)
+	private String id;
+
+	@Persistent
+	@Index(name = "USERID_IDX")
+	@Column(name = "USERID", length = 24)
+	private String userid;
+
+	@Persistent
+	@Index(name = "CREATE_IDX")
+	@Column(name = "CREATE_DATE")
+	private Date createDate;
+
+	@Persistent
+	@Column(name = "USAGE_RECORD", jdbcType = "CLOB")
+	private String usageRecord;
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getUserid() {
+		return userid;
+	}
+
+	public void setUserid(String userid) {
+		this.userid = userid;
+	}
+
+	public Date getCreateDate() {
+		return createDate;
+	}
+
+	public void setCreateDate(Date createDate) {
+		this.createDate = createDate;
+	}
+
+	public String getUsageRecord() {
+		return usageRecord;
+	}
+
+	public void setUsageRecord(String usageRecord) {
+		this.usageRecord = usageRecord;
+	}
+}
\ No newline at end of file


[28/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Policy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Policy.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Policy.java
new file mode 100644
index 0000000..b09e0bd
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Policy.java
@@ -0,0 +1,133 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import java.net.URI;
+import java.util.List;
+
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Simple policy interface.
+ * 
+ * @author Donal Fellows
+ */
+public interface Policy {
+	/**
+	 * @return The maximum number of runs that the system can support.
+	 */
+	int getMaxRuns();
+
+	/**
+	 * Get the limit on the number of runs for this user.
+	 * 
+	 * @param user
+	 *            Who to get the limit for
+	 * @return The maximum number of runs for this user, or <tt>null</tt> if no
+	 *         per-user limit is imposed and only system-wide limits are to be
+	 *         enforced.
+	 */
+	Integer getMaxRuns(UsernamePrincipal user);
+
+	/**
+	 * Test whether the user can create an instance of the given workflow.
+	 * 
+	 * @param user
+	 *            Who wants to do the creation.
+	 * @param workflow
+	 *            The workflow they wish to instantiate.
+	 * @throws NoCreateException
+	 *             If they may not instantiate it.
+	 */
+	void permitCreate(UsernamePrincipal user, Workflow workflow)
+			throws NoCreateException;
+
+	/**
+	 * Test whether the user can destroy a workflow instance run or manipulate
+	 * its expiry date.
+	 * 
+	 * @param user
+	 *            Who wants to do the deletion.
+	 * @param run
+	 *            What they want to delete.
+	 * @throws NoDestroyException
+	 *             If they may not destroy it.
+	 */
+	void permitDestroy(UsernamePrincipal user, TavernaRun run)
+			throws NoDestroyException;
+
+	/**
+	 * Return whether the user has access to a particular workflow run.
+	 * <b>Note</b> that this does not throw any exceptions!
+	 * 
+	 * @param user
+	 *            Who wants to read the workflow's state.
+	 * @param run
+	 *            What do they want to read from.
+	 * @return Whether they can read it. Note that this check is always applied
+	 *         before testing whether the workflow can be updated or deleted by
+	 *         the user.
+	 */
+	boolean permitAccess(UsernamePrincipal user, TavernaRun run);
+
+	/**
+	 * Test whether the user can modify a workflow run (other than for its
+	 * expiry date).
+	 * 
+	 * @param user
+	 *            Who wants to do the modification.
+	 * @param run
+	 *            What they want to modify.
+	 * @throws NoUpdateException
+	 *             If they may not modify it.
+	 */
+	void permitUpdate(UsernamePrincipal user, TavernaRun run)
+			throws NoUpdateException;
+
+	/**
+	 * Get the URIs of the workflows that the given user may execute.
+	 * 
+	 * @param user
+	 *            Who are we finding out on behalf of.
+	 * @return A list of workflow URIs that they may instantiate, or
+	 *         <tt>null</tt> if any workflow may be submitted.
+	 */
+	List<URI> listPermittedWorkflowURIs(UsernamePrincipal user);
+
+	/**
+	 * @return The maximum number of {@linkplain Status#Operating operating}
+	 *         runs that the system can support.
+	 */
+	int getOperatingLimit();
+
+	/**
+	 * Set the URIs of the workflows that the given user may execute.
+	 * 
+	 * @param user
+	 *            Who are we finding out on behalf of.
+	 * @param permitted
+	 *            A list of workflow URIs that they may instantiate.
+	 */
+	void setPermittedWorkflowURIs(UsernamePrincipal user, List<URI> permitted);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/RunStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/RunStore.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/RunStore.java
new file mode 100644
index 0000000..b0d817a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/RunStore.java
@@ -0,0 +1,95 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import java.util.Map;
+
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Interface to the mechanism that looks after the mapping of names to runs.
+ * Instances of this class may also be responsible for enforcing timely cleanup
+ * of expired workflows.
+ * 
+ * @author Donal Fellows.
+ */
+public interface RunStore {
+	/**
+	 * Obtain the workflow run for a given user and name.
+	 * 
+	 * @param user
+	 *            Who wants to do the lookup.
+	 * @param p
+	 *            The general policy system context.
+	 * @param uuid
+	 *            The handle for the run.
+	 * @return The workflow instance run.
+	 * @throws UnknownRunException
+	 *             If the lookup fails (either because it does not exist or
+	 *             because it is not permitted for the user by the policy).
+	 */
+	TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
+			throws UnknownRunException;
+
+	/**
+	 * Obtain the named workflow run.
+	 * 
+	 * @param uuid
+	 *            The handle for the run.
+	 * @return The workflow instance run.
+	 * @throws UnknownRunException
+	 *             If the lookup fails (either because it does not exist or
+	 *             because it is not permitted for the user by the policy).
+	 */
+	public TavernaRun getRun(String uuid) throws UnknownRunException;
+
+	/**
+	 * List the runs that a particular user may access.
+	 * 
+	 * @param user
+	 *            Who wants to do the lookup, or <code>null</code> if it is
+	 *            being done "by the system" when the full mapping should be
+	 *            returned.
+	 * @param p
+	 *            The general policy system context.
+	 * @return A mapping from run names to run instances.
+	 */
+	Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p);
+
+	/**
+	 * Adds a workflow instance run to the store. Note that this operation is
+	 * <i>not</i> expected to be security-checked; that is the callers'
+	 * responsibility.
+	 * 
+	 * @param run
+	 *            The run itself.
+	 * @return The name of the run.
+	 */
+	String registerRun(TavernaRun run);
+
+	/**
+	 * Removes a run from the store. Note that this operation is <i>not</i>
+	 * expected to be security-checked; that is the callers' responsibility.
+	 * 
+	 * @param uuid
+	 *            The name of the run.
+	 */
+	void unregisterRun(String uuid);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/SecurityContextFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/SecurityContextFactory.java
new file mode 100644
index 0000000..a0cac79
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/SecurityContextFactory.java
@@ -0,0 +1,45 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * How to create instances of a security context.
+ * 
+ * @author Donal Fellows
+ */
+public interface SecurityContextFactory extends Serializable {
+	/**
+	 * Creates a security context.
+	 * 
+	 * @param run
+	 *            Handle to remote run. Allows the security context to know how
+	 *            to apply itself to the workflow run.
+	 * @param owner
+	 *            The identity of the owner of the workflow run.
+	 * @return The security context.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	TavernaSecurityContext create(TavernaRun run, UsernamePrincipal owner)
+			throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaRun.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaRun.java
new file mode 100644
index 0000000..8d9a7f8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaRun.java
@@ -0,0 +1,232 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+
+/**
+ * The interface to a taverna workflow run, or "run" for short.
+ * 
+ * @author Donal Fellows
+ */
+public interface TavernaRun extends Serializable {
+	/**
+	 * @return The identifier of the run.
+	 */
+	String getId();
+
+	/**
+	 * @return What was this run was create to execute.
+	 */
+	Workflow getWorkflow();
+
+	/**
+	 * @return The name of the run.
+	 */
+	String getName();
+
+	/**
+	 * @param name
+	 *            The new name of the run. May be truncated.
+	 */
+	void setName(String name);
+
+	/**
+	 * @return The name of the Baclava file to use for all inputs, or
+	 *         <tt>null</tt> if no Baclava file is set.
+	 */
+	String getInputBaclavaFile();
+
+	/**
+	 * 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 FilesystemAccessException
+	 *             If the filename is invalid.
+	 * @throws BadStateChangeException
+	 *             If the workflow is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	void setInputBaclavaFile(String filename) throws FilesystemAccessException,
+			BadStateChangeException;
+
+	/**
+	 * @return The list of input assignments.
+	 */
+	List<Input> getInputs();
+
+	/**
+	 * Create an input assignment.
+	 * 
+	 * @param name
+	 *            The name of the port that this will be an input for.
+	 * @return The assignment reference.
+	 * @throws BadStateChangeException
+	 *             If the workflow is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	Input makeInput(String name) throws BadStateChangeException;
+
+	/**
+	 * @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>.
+	 */
+	String getOutputBaclavaFile();
+
+	/**
+	 * 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 FilesystemAccessException
+	 *             If the filename starts with a <tt>/</tt> or contains a
+	 *             <tt>..</tt> segment.
+	 * @throws BadStateChangeException
+	 *             If the workflow is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	void setOutputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException;
+
+	/**
+	 * @return When this run will expire, becoming eligible for automated
+	 *         deletion.
+	 */
+	Date getExpiry();
+
+	/**
+	 * Set when this run will expire.
+	 * 
+	 * @param d
+	 *            Expiry time. Deletion will happen some time after that.
+	 */
+	void setExpiry(Date d);
+
+	/**
+	 * @return The current status of the run.
+	 */
+	Status getStatus();
+
+	/**
+	 * 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.
+	 * @return <tt>null</tt>, or a string describing the incomplete state change
+	 *         if the operation has internally timed out.
+	 * @throws BadStateChangeException
+	 *             If the change to the given state is impossible.
+	 */
+	String setStatus(Status s) throws BadStateChangeException;
+
+	/**
+	 * @return Handle to the main working directory of the run.
+	 * @throws FilesystemAccessException
+	 */
+	Directory getWorkingDirectory() throws FilesystemAccessException;
+
+	/**
+	 * @return The list of listener instances attached to the run.
+	 */
+	List<Listener> getListeners();
+
+	/**
+	 * Add a listener to the run.
+	 * 
+	 * @param listener
+	 *            The listener to add.
+	 */
+	void addListener(Listener listener);
+
+	/**
+	 * @return The security context structure for this run.
+	 */
+	TavernaSecurityContext getSecurityContext();
+
+	/**
+	 * Kill off this run, removing all resources which it consumes.
+	 * 
+	 * @throws NoDestroyException
+	 *             If the destruction failed.
+	 */
+	void destroy() throws NoDestroyException;
+
+	/**
+	 * @return When this workflow run was created.
+	 */
+	Date getCreationTimestamp();
+
+	/**
+	 * @return When this workflow run was started, or <tt>null</tt> if it has
+	 *         never been started.
+	 */
+	Date getStartTimestamp();
+
+	/**
+	 * @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).
+	 */
+	Date getFinishTimestamp();
+
+	/**
+	 * Test if this run is really there.
+	 * 
+	 * <p>
+	 * <i>Implementation note:</i> Used to test communication fabrics, etc. so
+	 * implementations of this interface that do not delegate to another object
+	 * should do nothing.
+	 * 
+	 * @throws UnknownRunException
+	 *             If things fail.
+	 */
+	void ping() throws UnknownRunException;
+
+	/**
+	 * @return whether the run generates provenance data
+	 */
+	boolean getGenerateProvenance();
+
+	/**
+	 * @param generateProvenance
+	 *            whether the run generates provenance data
+	 */
+	void setGenerateProvenance(boolean generateProvenance);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaSecurityContext.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaSecurityContext.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaSecurityContext.java
new file mode 100644
index 0000000..3f993df
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/TavernaSecurityContext.java
@@ -0,0 +1,226 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.util.Set;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.xml.ws.handler.MessageContext;
+
+import org.springframework.security.core.context.SecurityContext;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Security context for a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+public interface TavernaSecurityContext {
+	/**
+	 * @return Who owns the security context.
+	 */
+	UsernamePrincipal getOwner();
+
+	/**
+	 * Describe the names of the users (as extracted from their
+	 * {@link Principal} objects) that may destroy the run or manipulate its
+	 * lifetime.
+	 * 
+	 * @return The names of the users who may use destroy operations. Read-only.
+	 */
+	Set<String> getPermittedDestroyers();
+
+	/**
+	 * Sets the collection of names of users (as extracted from their
+	 * {@link Principal} objects) that may destroy the run or manipulate its
+	 * lifetime.
+	 * 
+	 * @param destroyers
+	 *            The names of the users who may use destroy operations.
+	 */
+	void setPermittedDestroyers(Set<String> destroyers);
+
+	/**
+	 * Describe the names of the users (as extracted from their
+	 * {@link Principal} objects) that may update the run (including writing to
+	 * files).
+	 * 
+	 * @return The names of the users who may use update operations. Read-only.
+	 */
+	Set<String> getPermittedUpdaters();
+
+	/**
+	 * Sets the collection of names of users (as extracted from their
+	 * {@link Principal} objects) that may update the run (including writing to
+	 * its files).
+	 * 
+	 * @param updaters
+	 *            The names of the users who may use update operations.
+	 */
+	void setPermittedUpdaters(Set<String> updaters);
+
+	/**
+	 * Describe the names of the users (as extracted from their
+	 * {@link Principal} objects) that may read from the run (including its
+	 * files).
+	 * 
+	 * @return The names of the users who may use read operations. Read-only.
+	 */
+	Set<String> getPermittedReaders();
+
+	/**
+	 * Sets the collection of names of users (as extracted from their
+	 * {@link Principal} objects) that may read from the run (including its
+	 * files).
+	 * 
+	 * @param readers
+	 *            The names of the users who may use read operations.
+	 */
+	void setPermittedReaders(Set<String> readers);
+
+	/**
+	 * @return The credentials owned by the user. Never <tt>null</tt>.
+	 */
+	Credential[] getCredentials();
+
+	/**
+	 * Add a credential to the owned set or replaces the old version with the
+	 * new one.
+	 * 
+	 * @param toAdd
+	 *            The credential to add.
+	 */
+	void addCredential(Credential toAdd);
+
+	/**
+	 * Remove a credential from the owned set. It's not a failure to remove
+	 * something that isn't in the set.
+	 * 
+	 * @param toDelete
+	 *            The credential to remove.
+	 */
+	void deleteCredential(Credential toDelete);
+
+	/**
+	 * Tests if the credential is valid. This includes testing whether the
+	 * underlying credential file exists and can be unlocked by the password in
+	 * the {@link Credential} object.
+	 * 
+	 * @param c
+	 *            The credential object to validate.
+	 * @throws InvalidCredentialException
+	 *             If it is invalid.
+	 */
+	void validateCredential(Credential c) throws InvalidCredentialException;
+
+	/**
+	 * @return The identities trusted by the user. Never <tt>null</tt>.
+	 */
+	Trust[] getTrusted();
+
+	/**
+	 * Add an identity to the trusted set.
+	 * 
+	 * @param toAdd
+	 *            The identity to add.
+	 */
+	void addTrusted(Trust toAdd);
+
+	/**
+	 * Remove an identity from the trusted set. It's not a failure to remove
+	 * something that isn't in the set.
+	 * 
+	 * @param toDelete
+	 *            The identity to remove.
+	 */
+	void deleteTrusted(Trust toDelete);
+
+	/**
+	 * Tests if the trusted identity descriptor is valid. This includes checking
+	 * whether the underlying trusted identity file exists.
+	 * 
+	 * @param t
+	 *            The trusted identity descriptor to check.
+	 * @throws InvalidCredentialException
+	 *             If it is invalid.
+	 */
+	void validateTrusted(Trust t) throws InvalidCredentialException;
+
+	/**
+	 * Establish the security context from how the owning workflow run was
+	 * created. In particular, this gives an opportunity for boot-strapping
+	 * things with any delegateable credentials.
+	 * 
+	 * @param securityContext
+	 *            The security context associated with the request that caused
+	 *            the workflow to be created.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	void initializeSecurityFromContext(SecurityContext securityContext)
+			throws Exception;
+
+	/**
+	 * Establish the security context from how the owning workflow run was
+	 * created. In particular, this gives an opportunity for boot-strapping
+	 * things with any delegateable credentials.
+	 * 
+	 * @param context
+	 *            The full information about the request that caused the
+	 *            workflow to be created.
+	 */
+	void initializeSecurityFromSOAPContext(MessageContext context);
+
+	/**
+	 * Establish the security context from how the owning workflow run was
+	 * created. In particular, this gives an opportunity for boot-strapping
+	 * things with any delegateable credentials.
+	 * 
+	 * @param headers
+	 *            The full information about the request that caused the
+	 *            workflow to be created.
+	 */
+	void initializeSecurityFromRESTContext(HttpHeaders headers);
+
+	/**
+	 * Transfer the security context to the remote system.
+	 * 
+	 * @throws IOException
+	 *             If the communication fails.
+	 * @throws GeneralSecurityException
+	 *             If the assembly of the context fails.
+	 * @throws ImplementationException
+	 *             If the local worker has problems with creating the realized
+	 *             security context.
+	 */
+	void conveySecurity() throws GeneralSecurityException, IOException,
+			ImplementationException;
+
+	/**
+	 * @return The factory that created this security context.
+	 */
+	SecurityContextFactory getFactory();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/UriBuilderFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/UriBuilderFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/UriBuilderFactory.java
new file mode 100644
index 0000000..c4d0fb5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/UriBuilderFactory.java
@@ -0,0 +1,56 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import java.net.URI;
+
+import javax.ws.rs.core.UriBuilder;
+
+/**
+ * How to manufacture URIs to workflow runs.
+ * 
+ * @author Donal Fellows
+ */
+public interface UriBuilderFactory {
+	/**
+	 * Given a run, get a factory for RESTful URIs to resources associated
+	 * with it.
+	 * 
+	 * @param run
+	 *            The run in question.
+	 * @return The {@link URI} factory.
+	 */
+	UriBuilder getRunUriBuilder(TavernaRun run);
+
+	/**
+	 * @return a URI factory that is preconfigured to point to the base of
+	 *         the webapp.
+	 */
+	UriBuilder getBaseUriBuilder();
+
+	/**
+	 * Resolves a URI with respect to the base URI of the factory.
+	 * 
+	 * @param uri
+	 *            The URI to resolve, or <tt>null</tt>.
+	 * @return The resolved URI, or <tt>null</tt> if <b>uri</b> is
+	 *         <tt>null</tt>.
+	 */
+	String resolve(String uri);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/package-info.java
new file mode 100644
index 0000000..9c9b5b8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/package-info.java
@@ -0,0 +1,23 @@
+/*
+ */
+/**
+ * Interfaces to the main worker classes that provide the magical power
+ * that drives the webapp front-end.
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/AbstractRemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/AbstractRemoteRunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/AbstractRemoteRunFactory.java
new file mode 100644
index 0000000..72004b4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/AbstractRemoteRunFactory.java
@@ -0,0 +1,452 @@
+/*
+ */
+package org.taverna.server.master.localworker;
+/*
+ * 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.
+ */
+
+import static java.lang.System.getSecurityManager;
+import static java.lang.System.setProperty;
+import static java.lang.System.setSecurityManager;
+import static java.rmi.registry.LocateRegistry.createRegistry;
+import static java.rmi.registry.LocateRegistry.getRegistry;
+import static java.rmi.registry.Registry.REGISTRY_PORT;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.URI;
+import java.net.URL;
+import java.rmi.MarshalledObject;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.Resource;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.localworker.remote.RemoteRunFactory;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.factories.ListenerFactory;
+import org.taverna.server.master.factories.RunFactory;
+import org.taverna.server.master.interaction.InteractionFeedSupport;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.SecurityContextFactory;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.notification.atom.EventDAO;
+import org.taverna.server.master.usage.UsageRecordRecorder;
+import org.taverna.server.master.utils.UsernamePrincipal;
+import org.taverna.server.master.worker.FactoryBean;
+import org.taverna.server.master.worker.RemoteRunDelegate;
+import org.taverna.server.master.worker.RunFactoryConfiguration;
+
+import org.apache.taverna.scufl2.api.io.WriterException;
+
+/**
+ * Bridge to remote runs via RMI.
+ * 
+ * @author Donal Fellows
+ */
+@ManagedResource(objectName = JMX_ROOT + "Factory", description = "The factory for runs")
+public abstract class AbstractRemoteRunFactory extends RunFactoryConfiguration
+		implements ListenerFactory, RunFactory, FactoryBean {
+	/**
+	 * Whether to apply stronger limitations than normal to RMI. It is
+	 * recommended that this be true!
+	 */
+	@Value("${rmi.localhostOnly}")
+	private boolean rmiLocalhostOnly;
+	/** The interaction host name. */
+	private String interhost;
+	/** The interaction port number. */
+	private String interport;
+	private Process registryProcess;
+	/**
+	 * The interaction WebDAV location. Will be resolved before being passed to
+	 * the back-end.
+	 */
+	private String interwebdav;
+	/**
+	 * The interaction ATOM feed location. Will be resolved before being passed
+	 * to the back-end.
+	 */
+	private String interfeed;
+	/** Used for doing URI resolution. */
+	@Resource(name = "webapp")
+	private UriBuilderFactory baseurifactory;
+	@Autowired
+	private InteractionFeedSupport interactionFeedSupport;
+
+	@Value("${taverna.interaction.host}")
+	void setInteractionHost(String host) {
+		if (host != null && host.equals("none"))
+			host = null;
+		interhost = host;
+	}
+
+	@Value("${taverna.interaction.port}")
+	void setInteractionPort(String port) {
+		if (port != null && port.equals("none"))
+			port = null;
+		interport = port;
+	}
+
+	@Value("${taverna.interaction.webdav_path}")
+	void setInteractionWebdav(String webdav) {
+		if (webdav != null && webdav.equals("none"))
+			webdav = null;
+		interwebdav = webdav;
+	}
+
+	@Value("${taverna.interaction.feed_path}")
+	void setInteractionFeed(String feed) {
+		if (feed != null && feed.equals("none"))
+			feed = null;
+		interfeed = feed;
+	}
+
+	@Override
+	protected void reinitRegistry() {
+		registry = null;
+		if (registryProcess != null) {
+			registryProcess.destroy();
+			registryProcess = null;
+		}
+	}
+
+	protected void initInteractionDetails(RemoteRunFactory factory)
+			throws RemoteException {
+		if (interhost != null) {
+			String feed = baseurifactory.resolve(interfeed);
+			String webdav = baseurifactory.resolve(interwebdav);
+			factory.setInteractionServiceDetails(interhost, interport, webdav,
+					feed);
+		}
+	}
+
+	protected static final Process launchSubprocess(ProcessBuilder b)
+			throws IOException {
+		Thread t = Thread.currentThread();
+		ClassLoader ccl = t.getContextClassLoader();
+		try {
+			t.setContextClassLoader(null);
+			return b.start();
+		} finally {
+			t.setContextClassLoader(ccl);
+		}
+	}
+
+	/** Get a handle to a new instance of the RMI registry. */
+	private Registry makeRegistry(int port) throws RemoteException {
+		ProcessBuilder p = new ProcessBuilder(getJavaBinary());
+		p.command().add("-jar");
+		p.command().add(getRmiRegistryJar());
+		p.command().add(Integer.toString(port));
+		p.command().add(Boolean.toString(rmiLocalhostOnly));
+		try {
+			Process proc = launchSubprocess(p);
+			Thread.sleep(getSleepTime());
+			try {
+				if (proc.exitValue() == 0)
+					return null;
+				String error = IOUtils.toString(proc.getErrorStream());
+				throw new RemoteException(error);
+			} catch (IllegalThreadStateException ise) {
+				// Still running!
+			}
+			try (ObjectInputStream ois = new ObjectInputStream(
+					proc.getInputStream())) {
+				@SuppressWarnings("unchecked")
+				Registry r = ((MarshalledObject<Registry>) ois.readObject())
+						.get();
+				registryProcess = proc;
+				return r;
+			}
+		} catch (RemoteException e) {
+			throw e;
+		} catch (ClassNotFoundException e) {
+			throw new RemoteException("unexpected registry type", e);
+		} catch (IOException e) {
+			throw new RemoteException("unexpected IO problem with registry", e);
+		} catch (InterruptedException e) {
+			throw new RemoteException("unexpected interrupt");
+		}
+	}
+
+	/**
+	 * @return A handle to the current RMI registry.
+	 */
+	protected Registry getTheRegistry() {
+		try {
+			if (registry != null) {
+				registry.list();
+				return registry;
+			}
+		} catch (RemoteException e) {
+			log.warn("non-functioning existing registry handle", e);
+			registry = null;
+		}
+		try {
+			registry = getRegistry(getRegistryHost(), getRegistryPort());
+			registry.list();
+			return registry;
+		} catch (RemoteException e) {
+			log.warn("Failed to get working RMI registry handle.");
+			registry = null;
+			log.warn("Will build new registry, "
+					+ "but service restart ability is at risk.");
+			try {
+				registry = makeRegistry(getRegistryPort());
+				registry.list();
+				return registry;
+			} catch (RemoteException e2) {
+				log.error(
+						"failed to create local working RMI registry on port "
+								+ getRegistryPort(), e2);
+				log.info("original connection exception", e);
+			}
+		}
+		try {
+			registry = getRegistry(getRegistryHost(), REGISTRY_PORT);
+			registry.list();
+			return registry;
+		} catch (RemoteException e) {
+			log.warn("Failed to get working RMI registry handle on backup port.");
+			try {
+				registry = makeRegistry(REGISTRY_PORT);
+				registry.list();
+				return registry;
+			} catch (RemoteException e2) {
+				log.fatal(
+						"totally failed to get registry handle, even on fallback!",
+						e2);
+				log.info("original connection exception", e);
+				registry = null;
+				throw new RuntimeException("No RMI Registry Available");
+			}
+		}
+	}
+
+	private Registry registry;
+	/**
+	 * The name of the resource that describes the default security policy to
+	 * install.
+	 */
+	public static final String SECURITY_POLICY_FILE = "security.policy";
+	private SecurityContextFactory securityFactory;
+	UsageRecordRecorder usageRecordSink;
+	private EventDAO masterEventFeed;
+
+	@Autowired(required = true)
+	void setSecurityContextFactory(SecurityContextFactory factory) {
+		this.securityFactory = factory;
+	}
+
+	@Autowired(required = true)
+	void setMasterEventFeed(EventDAO masterEventFeed) {
+		this.masterEventFeed = masterEventFeed;
+	}
+
+	@Autowired(required = true)
+	void setUsageRecordSink(UsageRecordRecorder usageRecordSink) {
+		this.usageRecordSink = usageRecordSink;
+	}
+
+	/**
+	 * Configures the Java security model. Not currently used, as it is
+	 * viciously difficult to get right!
+	 */
+	@SuppressWarnings("unused")
+	private static void installSecurityManager() {
+		if (getSecurityManager() == null) {
+			setProperty("java.security.policy", AbstractRemoteRunFactory.class
+					.getClassLoader().getResource(SECURITY_POLICY_FILE)
+					.toExternalForm());
+			setSecurityManager(new SecurityManager());
+		}
+	}
+
+	// static {
+	// installSecurityManager();
+	// }
+
+	/**
+	 * Set up the run expiry management engine.
+	 * 
+	 * @throws JAXBException
+	 */
+	public AbstractRemoteRunFactory() throws JAXBException {
+		try {
+			registry = LocateRegistry.getRegistry();
+			registry.list();
+		} catch (RemoteException e) {
+			log.warn("Failed to get working RMI registry handle.");
+			log.warn("Will build new registry, but service restart ability is at risk.");
+			try {
+				registry = createRegistry(REGISTRY_PORT);
+				registry.list();
+			} catch (RemoteException e2) {
+				log.error("failed to create working RMI registry", e2);
+				log.info("original connection exception", e);
+			}
+		}
+	}
+
+	@Override
+	public List<String> getSupportedListenerTypes() {
+		try {
+			RemoteRunDelegate rrd = runDB.pickArbitraryRun();
+			if (rrd != null)
+				return rrd.getListenerTypes();
+			log.warn("no remote runs; no listener types");
+		} catch (Exception e) {
+			log.warn("failed to get list of listener types", e);
+		}
+		return new ArrayList<>();
+	}
+
+	@Override
+	public Listener makeListener(TavernaRun run, String listenerType,
+			String configuration) throws NoListenerException {
+		if (run instanceof RemoteRunDelegate)
+			return ((RemoteRunDelegate) run).makeListener(listenerType,
+					configuration);
+		throw new NoListenerException("unexpected run type: " + run.getClass());
+	}
+
+	@Override
+	public TavernaRun create(UsernamePrincipal creator, Workflow workflow)
+			throws NoCreateException {
+		try {
+			Date now = new Date();
+			UUID id = randomUUID();
+			RemoteSingleRun rsr = getRealRun(creator, workflow, id);
+			RemoteRunDelegate run = new RemoteRunDelegate(now, workflow, rsr,
+					state.getDefaultLifetime(), runDB, id,
+					state.getGenerateProvenance(), this);
+			run.setSecurityContext(securityFactory.create(run, creator));
+			@Nonnull
+			URI feed = interactionFeedSupport.getFeedURI(run);
+			@Nonnull
+			URL feedUrl = feed.toURL();
+			@Nonnull
+			URL webdavUrl = baseurifactory.getRunUriBuilder(run)
+					.path(DIR + "/interactions").build().toURL();
+			@Nullable
+			URL pub = interactionFeedSupport.getLocalFeedBase(feed);
+			rsr.setInteractionServiceDetails(feedUrl, webdavUrl, pub);
+			return run;
+		} catch (NoCreateException e) {
+			log.warn("failed to build run instance", e);
+			throw e;
+		} catch (Exception e) {
+			log.warn("failed to build run instance", e);
+			throw new NoCreateException("failed to build run instance", e);
+		}
+	}
+
+	/**
+	 * Gets the RMI connector for a new run.
+	 * 
+	 * @param creator
+	 *            Who is creating the workflow run.
+	 * @param workflow
+	 *            What workflow are they instantiating.
+	 * @param id
+	 *            The identity token for the run, newly minted.
+	 * @return The remote interface to the run.
+	 * @throws Exception
+	 *             Just about anything can go wrong...
+	 */
+	protected abstract RemoteSingleRun getRealRun(UsernamePrincipal creator,
+			Workflow workflow, UUID id) throws Exception;
+
+	/**
+	 * How to convert a wrapped workflow into XML.
+	 * 
+	 * @param workflow
+	 *            The wrapped workflow.
+	 * @return The XML version of the document.
+	 * @throws JAXBException
+	 *             If serialization fails.
+	 */
+	protected byte[] serializeWorkflow(Workflow workflow) throws JAXBException {
+		try {
+			return workflow.getScufl2Bytes();
+		} catch (IOException e) {
+			throw new JAXBException("problem converting to scufl2", e);
+		} catch (WriterException e) {
+			throw new JAXBException("problem converting to scufl2", e);
+		}
+	}
+
+	private void acceptUsageRecord(String usageRecord) {
+		if (usageRecordSink != null)
+			usageRecordSink.storeUsageRecord(usageRecord);
+		runDB.checkForFinishNow();
+	}
+
+	/**
+	 * Make a Remote object that can act as a consumer for usage records.
+	 * 
+	 * @param creator
+	 * 
+	 * @return The receiver, or <tt>null</tt> if the construction fails.
+	 */
+	protected UsageRecordReceiver makeURReciver(UsernamePrincipal creator) {
+		try {
+			@SuppressWarnings("serial")
+			class URReceiver extends UnicastRemoteObject implements
+					UsageRecordReceiver {
+				public URReceiver() throws RemoteException {
+					super();
+				}
+
+				@Override
+				public void acceptUsageRecord(String usageRecord) {
+					AbstractRemoteRunFactory.this.acceptUsageRecord(usageRecord);
+				}
+			}
+			return new URReceiver();
+		} catch (RemoteException e) {
+			log.warn("failed to build usage record receiver", e);
+			return null;
+		}
+	}
+
+	@Override
+	public EventDAO getMasterEventFeed() {
+		return masterEventFeed;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/ForkRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/ForkRunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/ForkRunFactory.java
new file mode 100644
index 0000000..3f48644
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/ForkRunFactory.java
@@ -0,0 +1,336 @@
+/*
+ */
+package org.taverna.server.master.localworker;
+/*
+ * 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.
+ */
+
+import static java.lang.System.getProperty;
+import static java.lang.Thread.sleep;
+import static java.util.Arrays.asList;
+import static java.util.Calendar.SECOND;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+
+import java.io.File;
+import java.rmi.ConnectException;
+import java.rmi.ConnectIOException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.util.Calendar;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.xml.bind.JAXBException;
+
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.localworker.remote.RemoteRunFactory;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.factories.ConfigurableRunFactory;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A simple factory for workflow runs that forks runs from a subprocess.
+ * 
+ * @author Donal Fellows
+ */
+@ManagedResource(objectName = JMX_ROOT + "RunFactory", description = "The factory for simple singleton forked run.")
+public class ForkRunFactory extends AbstractRemoteRunFactory implements
+		ConfigurableRunFactory {
+	private int lastStartupCheckCount;
+	private Integer lastExitCode;
+	private RemoteRunFactory factory;
+	private Process factoryProcess;
+	private String factoryProcessName;
+
+	/**
+	 * Create a factory for remote runs that works by forking off a subprocess.
+	 * 
+	 * @throws JAXBException
+	 *             Shouldn't happen.
+	 */
+	public ForkRunFactory() throws JAXBException {
+	}
+
+	@PostConstruct
+	protected void initRegistry() {
+		log.info("waiting for availability of default RMI registry");
+		getTheRegistry();
+	}
+
+	@Override
+	protected void reinitFactory() {
+		boolean makeFactory = factory != null;
+		killFactory();
+		try {
+			if (makeFactory)
+				initFactory();
+		} catch (Exception e) {
+			log.fatal("failed to make connection to remote run factory", e);
+		}
+	}
+
+	private RemoteRunFactory getFactory() throws RemoteException {
+		try {
+			initFactory();
+		} catch (RemoteException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new RemoteException("problem constructing factory", e);
+		}
+		return factory;
+	}
+
+	/**
+	 * @return How many checks were done for the worker process the last time a
+	 *         spawn was tried.
+	 */
+	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
+	@Override
+	public int getLastStartupCheckCount() {
+		return lastStartupCheckCount;
+	}
+
+	/**
+	 * @return What was the exit code from the last time the factory subprocess
+	 *         was killed?
+	 */
+	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
+	@Override
+	public Integer getLastExitCode() {
+		return lastExitCode;
+	}
+
+	/**
+	 * @return What the factory subprocess's main RMI interface is registered
+	 *         as.
+	 */
+	@ManagedAttribute(description = "What the factory subprocess's main RMI interface is registered as.", currencyTimeLimit = 60)
+	@Override
+	public String getFactoryProcessName() {
+		return factoryProcessName;
+	}
+
+	/**
+	 * Makes the subprocess that manufactures runs.
+	 * 
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	public void initFactory() throws Exception {
+		if (factory != null)
+			return;
+		// Generate the arguments to use when spawning the subprocess
+		factoryProcessName = state.getFactoryProcessNamePrefix() + randomUUID();
+		ProcessBuilder p = new ProcessBuilder(getJavaBinary());
+		p.command().add("-jar");
+		p.command().add(getServerWorkerJar());
+		if (getExecuteWorkflowScript() == null)
+			log.fatal("no execute workflow script");
+		p.command().add(getExecuteWorkflowScript());
+		p.command().addAll(asList(getExtraArguments()));
+		p.command().add(factoryProcessName);
+		p.redirectErrorStream(true);
+		p.directory(new File(getProperty("javax.servlet.context.tempdir",
+				getProperty("java.io.tmpdir"))));
+
+		// Spawn the subprocess
+		log.info("about to create subprocess: " + p.command());
+		
+		factoryProcess = launchSubprocess(p);
+		outlog = new StreamLogger("FactoryStdout", factoryProcess.getInputStream()) {
+			@Override
+			protected void write(String msg) {
+				log.info(msg);
+			}
+		};
+		errlog = new StreamLogger("FactoryStderr", factoryProcess.getErrorStream()) {
+			@Override
+			protected void write(String msg) {
+				log.info(msg);
+			}
+		};
+
+		// Wait for the subprocess to register itself in the RMI registry
+		Calendar deadline = Calendar.getInstance();
+		deadline.add(SECOND, state.getWaitSeconds());
+		Exception lastException = null;
+		lastStartupCheckCount = 0;
+		while (deadline.after(Calendar.getInstance())) {
+			try {
+				sleep(state.getSleepMS());
+				lastStartupCheckCount++;
+				factory = getRemoteFactoryHandle(factoryProcessName);
+				initInteractionDetails(factory);
+				return;
+			} catch (InterruptedException ie) {
+				continue;
+			} catch (NotBoundException nbe) {
+				lastException = nbe;
+				log.info("resource \"" + factoryProcessName
+						+ "\" not yet registered...");
+				continue;
+			} catch (RemoteException re) {
+				// Unpack a remote exception if we can
+				lastException = re;
+				try {
+					if (re.getCause() != null)
+						lastException = (Exception) re.getCause();
+				} catch (Throwable t) {
+					// Ignore!
+				}
+			} catch (RuntimeException e) {
+				lastException = e;
+			}
+		}
+		if (lastException == null)
+			lastException = new InterruptedException();
+		throw lastException;
+	}
+
+	private StreamLogger outlog, errlog;
+
+	private void stopLoggers() {
+		if (outlog != null)
+			outlog.stop();
+		outlog = null;
+		if (errlog != null)
+			errlog.stop();
+		errlog = null;
+	}
+
+	private RemoteRunFactory getRemoteFactoryHandle(String name)
+			throws RemoteException, NotBoundException {
+		log.info("about to look up resource called " + name);
+		try {
+			// Validate registry connection first
+			getTheRegistry().list();
+		} catch (ConnectException | ConnectIOException e) {
+			log.warn("connection problems with registry", e);
+		}
+		RemoteRunFactory rrf = (RemoteRunFactory) getTheRegistry().lookup(name);
+		log.info("successfully connected to factory subprocess "
+				+ factoryProcessName);
+		return rrf;
+	}
+
+	/**
+	 * Destroys the subprocess that manufactures runs.
+	 */
+	@PreDestroy
+	public void killFactory() {
+		if (factory != null) {
+			log.info("requesting shutdown of " + factoryProcessName);
+			try {
+				factory.shutdown();
+				sleep(700);
+			} catch (RemoteException e) {
+				log.warn(factoryProcessName + " failed to shut down nicely", e);
+			} catch (InterruptedException e) {
+				if (log.isDebugEnabled())
+					log.debug("interrupted during wait after asking "
+							+ factoryProcessName + " to shut down", e);
+			} finally {
+				factory = null;
+			}
+		}
+
+		if (factoryProcess != null) {
+			int code = -1;
+			try {
+				lastExitCode = code = factoryProcess.exitValue();
+				log.info(factoryProcessName + " already dead?");
+			} catch (RuntimeException e) {
+				log.info("trying to force death of " + factoryProcessName);
+				try {
+					factoryProcess.destroy();
+					sleep(350); // takes a little time, even normally
+					lastExitCode = code = factoryProcess.exitValue();
+				} catch (Exception e2) {
+					code = -1;
+				}
+			} finally {
+				factoryProcess = null;
+				stopLoggers();
+			}
+			if (code > 128) {
+				log.info(factoryProcessName + " died with signal="
+						+ (code - 128));
+			} else if (code >= 0) {
+				log.info(factoryProcessName + " process killed: code=" + code);
+			} else {
+				log.warn(factoryProcessName + " not yet dead");
+			}
+		}
+	}
+
+	/**
+	 * The real core of the run builder, factored out from its reliability
+	 * support.
+	 * 
+	 * @param creator
+	 *            Who created this workflow?
+	 * @param wf
+	 *            The serialized workflow.
+	 * @return The remote handle of the workflow run.
+	 * @throws RemoteException
+	 *             If anything fails (communications error, etc.)
+	 */
+	private RemoteSingleRun getRealRun(@Nonnull UsernamePrincipal creator,
+			@Nonnull byte[] wf, UUID id) throws RemoteException {
+		@Nonnull
+		String globaluser = "Unknown Person";
+		if (creator != null)
+			globaluser = creator.getName();
+		RemoteSingleRun rsr = getFactory().make(wf, globaluser,
+				makeURReciver(creator), id);
+		incrementRunCount();
+		return rsr;
+	}
+
+	@Override
+	protected RemoteSingleRun getRealRun(UsernamePrincipal creator,
+			Workflow workflow, UUID id) throws Exception {
+		@Nonnull
+		byte[] wf = serializeWorkflow(workflow);
+		for (int i = 0; i < 3; i++) {
+			initFactory();
+			try {
+				return getRealRun(creator, wf, id);
+			} catch (ConnectException | ConnectIOException e) {
+				// factory was lost; try to recreate
+			}
+			killFactory();
+		}
+		throw new NoCreateException("total failure to connect to factory "
+				+ factoryProcessName + "despite attempting restart");
+	}
+
+	@Override
+	public String[] getFactoryProcessMapping() {
+		return new String[0];
+	}
+
+	@Override
+	protected int operatingCount() throws Exception {
+		return getFactory().countOperatingRuns();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/IdAwareForkRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/IdAwareForkRunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/IdAwareForkRunFactory.java
new file mode 100644
index 0000000..a2e5ff7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/IdAwareForkRunFactory.java
@@ -0,0 +1,529 @@
+/*
+ */
+package org.taverna.server.master.localworker;
+/*
+ * 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.
+ */
+
+import static java.lang.System.getProperty;
+import static java.lang.Thread.sleep;
+import static java.util.Arrays.asList;
+import static java.util.Calendar.SECOND;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.taverna.server.master.localworker.AbstractRemoteRunFactory.launchSubprocess;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.rmi.ConnectException;
+import java.rmi.ConnectIOException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.annotation.Order;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.localworker.remote.RemoteRunFactory;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.factories.ConfigurableRunFactory;
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A simple factory for workflow runs that forks runs from a subprocess.
+ * 
+ * @author Donal Fellows
+ */
+@ManagedResource(objectName = JMX_ROOT + "RunFactory", description = "The factory for a user-specific forked run.")
+public class IdAwareForkRunFactory extends AbstractRemoteRunFactory implements
+		ConfigurableRunFactory {
+	private MetaFactory forker;
+	private Map<String, RemoteRunFactory> factory;
+	private Map<String, String> factoryProcessName;
+
+	/**
+	 * Create a factory for remote runs that works by forking off a subprocess.
+	 * 
+	 * @throws JAXBException
+	 *             Shouldn't happen.
+	 */
+	public IdAwareForkRunFactory() throws JAXBException {
+		factory = new HashMap<>();
+		factoryProcessName = new HashMap<>();
+	}
+
+	@Override
+	protected void reinitFactory() {
+		boolean makeForker = forker != null;
+		try {
+			killForker();
+		} catch (Exception e) {
+			log.warn("exception when killing secure-fork process", e);
+		}
+		try {
+			if (makeForker)
+				initMetaFactory();
+		} catch (Exception e) {
+			log.fatal("failed to make secure-fork process", e);
+		}
+	}
+
+	/**
+	 * @return How many checks were done for the worker process the last time a
+	 *         spawn was tried.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
+	public int getLastStartupCheckCount() {
+		return forker == null ? 0 : forker.lastStartupCheckCount();
+	}
+
+	/**
+	 * @return What was the exit code from the last time the factory subprocess
+	 *         was killed?
+	 */
+	@Override
+	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
+	public Integer getLastExitCode() {
+		return forker == null ? null : forker.lastExitCode();
+	}
+
+	/**
+	 * @return The mapping of user names to RMI factory IDs.
+	 */
+	@Override
+	@ManagedAttribute(description = "The mapping of user names to RMI factory IDs.", currencyTimeLimit = 60)
+	public String[] getFactoryProcessMapping() {
+		ArrayList<String> result = new ArrayList<>();
+		ArrayList<String> keys = new ArrayList<>(factoryProcessName.keySet());
+		String[] ks = keys.toArray(new String[keys.size()]);
+		Arrays.sort(ks);
+		for (String k : ks) {
+			result.add(k);
+			result.add(factoryProcessName.get(k));
+		}
+		return result.toArray(new String[result.size()]);
+	}
+
+	/**
+	 * How construction of factories is actually done.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public interface MetaFactory {
+		/**
+		 * Make a factory for the given user.
+		 * 
+		 * @param username
+		 *            Who to make it for.
+		 * @return Handle of the factory.
+		 * @throws Exception
+		 *             If anything goes wrong.
+		 */
+		RemoteRunFactory make(String username) throws Exception;
+
+		/**
+		 * Shut down the meta-factory. It is not defined whether factories
+		 * created by it are also shut down at the same time.
+		 * 
+		 * @throws IOException
+		 *             If something goes wrong when communicating with the
+		 *             meta-factory.
+		 * @throws InterruptedException
+		 *             If something stops us waiting for the shut down to
+		 *             happen.
+		 */
+		void close() throws IOException, InterruptedException;
+
+		int lastStartupCheckCount();
+
+		Integer lastExitCode();
+	}
+
+	void registerFactory(String username, String fpn, RemoteRunFactory f) {
+		factoryProcessName.put(username, fpn);
+		factory.put(username, f);
+	}
+
+	/**
+	 * Makes the connection to the meta-factory that makes factories.
+	 * 
+	 * @throws IOException
+	 *             If the connection fails.
+	 */
+	@PostConstruct
+	void initMetaFactory() throws IOException {
+		log.info("waiting for availability of default RMI registry");
+		getTheRegistry();
+		log.info("constructing secure fork subprocess");
+		forker = new SecureFork(this, state, log);
+	}
+
+	private void killForker() throws IOException, InterruptedException {
+		try {
+			if (forker != null)
+				forker.close();
+		} finally {
+			forker = null;
+		}
+	}
+
+	/**
+	 * Makes the subprocess that manufactures runs.
+	 * 
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	private void initFactory(String username) throws Exception {
+		if (factory.containsKey(username))
+			return;
+		if (forker == null)
+			initMetaFactory();
+		forker.make(username);
+	}
+
+	/**
+	 * Destroys the subprocess that manufactures runs.
+	 */
+	@PreDestroy
+	public void killFactories() {
+		if (!factory.isEmpty()) {
+			Iterator<String> keys = factory.keySet().iterator();
+			while (keys.hasNext()) {
+				String key = keys.next();
+				log.info("requesting shutdown of "
+						+ factoryProcessName.get(key));
+				try {
+					factory.get(key).shutdown();
+				} catch (RemoteException e) {
+					log.warn(factoryProcessName.get(key)
+							+ " failed to shut down nicely", e);
+				} finally {
+					keys.remove();
+					factoryProcessName.remove(key);
+				}
+			}
+			try {
+				sleep(700);
+			} catch (InterruptedException e) {
+				if (log.isDebugEnabled())
+					log.debug("interrupted during wait after "
+							+ "asking factories to shut down", e);
+			}
+		}
+
+		try {
+			killForker();
+		} catch (Exception e) {
+			if (log.isDebugEnabled())
+				log.debug("exception in shutdown of secure-fork process", e);
+		}
+	}
+
+	@Override
+	protected void finalize() throws Throwable {
+		killFactories();
+		super.finalize();
+	}
+
+	@Autowired
+	public void setIdMapper(LocalIdentityMapper mapper) {
+		this.mapper = mapper;
+	}
+
+	private LocalIdentityMapper mapper;
+
+	/**
+	 * The real core of the run builder, factored out from its reliability
+	 * support.
+	 * 
+	 * @param creator
+	 *            Who created this workflow?
+	 * @param username
+	 *            What user account is this workflow to be executed in?
+	 * @param wf
+	 *            The serialized workflow.
+	 * @return The remote handle of the workflow run.
+	 * @throws RemoteException
+	 *             If anything fails (communications error, etc.)
+	 */
+	private RemoteSingleRun getRealRun(@Nonnull UsernamePrincipal creator,
+			@Nonnull String username, @Nonnull byte[] wf, UUID id)
+			throws RemoteException {
+		String globaluser = "Unknown Person";
+		if (creator != null)
+			globaluser = creator.getName();
+		RemoteSingleRun rsr = factory.get(username).make(wf, globaluser,
+				makeURReciver(creator), id);
+		incrementRunCount();
+		return rsr;
+	}
+
+	@Override
+	protected RemoteSingleRun getRealRun(UsernamePrincipal creator,
+			Workflow workflow, UUID id) throws Exception {
+		byte[] wf = serializeWorkflow(workflow);
+		String username = mapper == null ? null : mapper
+				.getUsernameForPrincipal(creator);
+		if (username == null)
+			throw new Exception("cannot determine who to run workflow as; "
+					+ "local identity mapper returned null");
+		for (int i = 0; i < 3; i++) {
+			if (!factory.containsKey(username))
+				initFactory(username);
+			try {
+				return getRealRun(creator, username, wf, id);
+			} catch (ConnectException | ConnectIOException e) {
+				// factory was lost; try to recreate
+			}
+			factory.remove(username);
+		}
+		throw new NoCreateException("total failure to connect to factory "
+				+ factoryProcessName + "despite attempting restart");
+	}
+
+	@Value("${secureForkPasswordFile}")
+	@Order(20)
+	public void setPasswordSource(String passwordSource) {
+		if (passwordSource == null || passwordSource.isEmpty()
+				|| passwordSource.startsWith("${"))
+			state.setDefaultPasswordFile(null);
+		else
+			state.setDefaultPasswordFile(passwordSource);
+		if (state.getPasswordFile() == null)
+			log.info("assuming password-free forking enabled");
+		else
+			log.info("configured secureForkPasswordFile from context as "
+					+ state.getPasswordFile());
+	}
+
+	@Override
+	public String getFactoryProcessName() {
+		return "<PROPERTY-NOT-SUPPORTED>";
+	}
+
+	@Override
+	protected int operatingCount() throws Exception {
+		int total = 0;
+		for (RemoteRunFactory rrf : factory.values())
+			total += rrf.countOperatingRuns();
+		return total;
+	}
+}
+
+/**
+ * The connector that handles the secure fork process itself.
+ * 
+ * @author Donal Fellows
+ */
+class SecureFork implements IdAwareForkRunFactory.MetaFactory {
+	private IdAwareForkRunFactory main;
+	private Process process;
+	private PrintWriter channel;
+	private int lastStartupCheckCount;
+	private Integer lastExitCode;
+	private Log log;
+	private LocalWorkerState state;
+	private StreamLogger out, err;
+
+	/**
+	 * Construct the command to run the meta-factory process.
+	 * 
+	 * @param args
+	 *            The live list of arguments to pass.
+	 */
+	public void initFactoryArgs(List<String> args) {
+		args.add(main.getJavaBinary());
+		String pwf = main.getPasswordFile();
+		if (pwf != null) {
+			args.add("-Dpassword.file=" + pwf);
+		}
+		args.add("-jar");
+		args.add(main.getServerForkerJar());
+		args.add(main.getJavaBinary());
+		args.add("-jar");
+		args.add(main.getServerWorkerJar());
+		if (main.getExecuteWorkflowScript() == null)
+			log.fatal("no execute workflow script");
+		args.add(main.getExecuteWorkflowScript());
+		args.addAll(asList(main.getExtraArguments()));
+	}
+
+	SecureFork(IdAwareForkRunFactory main, LocalWorkerState state, Log log)
+			throws IOException {
+		this.main = main;
+		this.log = log;
+		this.state = state;
+		ProcessBuilder p = new ProcessBuilder();
+		initFactoryArgs(p.command());
+		p.redirectErrorStream(true);
+		p.directory(new File(getProperty("javax.servlet.context.tempdir",
+				getProperty("java.io.tmpdir"))));
+
+		// Spawn the subprocess
+		log.info("about to create subprocess: " + p.command());
+		log.info("subprocess directory: " + p.directory());
+		process = launchSubprocess(p);
+		channel = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
+				process.getOutputStream())), true);
+		// Log the responses
+		out = new StreamLogger("ForkedStdout", process.getInputStream()) {
+			@Override
+			protected void write(String msg) {
+				log.info(msg);
+			}
+		};
+		err = new StreamLogger("ForkedStderr", process.getErrorStream()) {
+			@Override
+			protected void write(String msg) {
+				log.info(msg);
+			}
+		};
+	}
+
+	@Override
+	public void close() throws IOException, InterruptedException {
+		try {
+			if (process != null) {
+				log.info("about to close down subprocess");
+				channel.close();
+				int code = -1;
+				try {
+					try {
+						code = process.exitValue();
+						log.info("secure-fork process already dead?");
+					} catch (IllegalThreadStateException e) {
+						try {
+							code = process.waitFor();
+						} catch (InterruptedException e1) {
+							log.info("interrupted waiting for natural death of secure-fork process?!");
+							process.destroy();
+							code = process.waitFor();
+						}
+					}
+				} finally {
+					lastExitCode = code;
+					if (code > 128) {
+						log.info("secure-fork process died with signal="
+								+ (code - 128));
+					} else if (code >= 0) {
+						log.info("secure-fork process killed: code=" + code);
+					} else {
+						log.warn("secure-fork process not yet dead");
+					}
+				}
+			}
+		} finally {
+			process = null;
+			channel = null;
+			out.stop();
+			err.stop();
+		}
+	}
+
+	protected void make(String username, String fpn) {
+		log.info("about to request subprocess creation for " + username
+				+ " producing ID " + fpn);
+		channel.println(username + " " + fpn);
+	}
+
+	@Override
+	public RemoteRunFactory make(String username) throws Exception {
+		try {
+			main.getTheRegistry().list(); // Validate registry connection first
+		} catch (ConnectException | ConnectIOException e) {
+			log.warn("connection problems with registry", e);
+		} catch (RemoteException e) {
+			if (e.getCause() != null && e.getCause() instanceof Exception) {
+				throw (Exception) e.getCause();
+			}
+			log.warn("connection problems with registry", e);
+		}
+
+		String fpn = state.getFactoryProcessNamePrefix() + randomUUID();
+		make(username, fpn);
+
+		// Wait for the subprocess to register itself in the RMI registry
+		Calendar deadline = Calendar.getInstance();
+		deadline.add(SECOND, state.getWaitSeconds());
+		Exception lastException = null;
+		lastStartupCheckCount = 0;
+		while (deadline.after(Calendar.getInstance())) {
+			try {
+				sleep(state.getSleepMS());
+				lastStartupCheckCount++;
+				log.info("about to look up resource called " + fpn);
+				RemoteRunFactory f = (RemoteRunFactory) main.getTheRegistry()
+						.lookup(fpn);
+				log.info("successfully connected to factory subprocess " + fpn);
+				main.initInteractionDetails(f);
+				main.registerFactory(username, fpn, f);
+				return f;
+			} catch (InterruptedException ie) {
+				continue;
+			} catch (NotBoundException nbe) {
+				lastException = nbe;
+				log.info("resource \"" + fpn + "\" not yet registered...");
+				continue;
+			} catch (RemoteException re) {
+				// Unpack a remote exception if we can
+				lastException = re;
+				try {
+					if (re.getCause() != null)
+						lastException = (Exception) re.getCause();
+				} catch (Throwable t) {
+					// Ignore!
+				}
+			} catch (Exception e) {
+				lastException = e;
+			}
+		}
+		if (lastException == null)
+			lastException = new InterruptedException();
+		throw lastException;
+	}
+
+	@Override
+	public Integer lastExitCode() {
+		return lastExitCode;
+	}
+
+	@Override
+	public int lastStartupCheckCount() {
+		return lastStartupCheckCount;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerFactory.java
new file mode 100644
index 0000000..803c201
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerFactory.java
@@ -0,0 +1,44 @@
+/*
+ */
+package org.taverna.server.master.localworker;
+/*
+ * 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.
+ */
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Provider of the configuration of the "localworker.factory" bean, which is
+ * sufficiently complex to be too hard to manufacture directly from the XML
+ * configuration.
+ * 
+ * @author Donal Fellows
+ */
+@Configuration
+public class LocalWorkerFactory {
+	@Bean(name = "localworker.factory")
+	AbstractRemoteRunFactory getLocalworkerFactory(
+			@Value("${backEndFactory}") String mode) throws Exception {
+		if (mode == null || mode.isEmpty() || mode.startsWith("${"))
+			throw new Exception("no value for ${backEndFactory}");
+		Class<?> c = Class.forName(mode);
+		if (AbstractRemoteRunFactory.class.isAssignableFrom(c))
+			return (AbstractRemoteRunFactory) c.newInstance();
+		throw new Exception("unknown remote run factory: " + mode);
+	}
+}


[07/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
deleted file mode 100644
index 1bd2a95..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.apache.cxf.common.util.UrlUtils.parseQueryString;
-import static org.apache.cxf.message.Message.HTTP_REQUEST_METHOD;
-import static org.apache.cxf.message.Message.QUERY_STRING;
-import static org.apache.cxf.message.Message.REQUEST_URL;
-import static org.apache.cxf.phase.Phase.READ;
-
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.cxf.binding.soap.interceptor.EndpointSelectionInterceptor;
-import org.apache.cxf.interceptor.Fault;
-import org.apache.cxf.message.Message;
-import org.apache.cxf.phase.AbstractPhaseInterceptor;
-
-
-/**
- * Thunk for TAVSERV-293.
- * 
- * @author Donal Fellows (based on work by Daniel Hagen)
- */
-public class WSDLHeadOptionsInterceptor extends
-		AbstractPhaseInterceptor<Message> {
-	public static final Log log = getLog("Taverna.Server.Utils");
-
-	public WSDLHeadOptionsInterceptor() {
-		super(READ);
-		getAfter().add(EndpointSelectionInterceptor.class.getName());
-	}
-
-	@Override
-	public void handleMessage(Message message) throws Fault {
-		String method = (String) message.get(HTTP_REQUEST_METHOD);
-		String query = (String) message.get(QUERY_STRING);
-
-		if (("HEAD".equals(method) || "OPTIONS".equals(method))
-				&& query != null && !query.trim().isEmpty()
-				&& isRecognizedQuery(query)) {
-			log.debug("adjusting message request method " + method + " for "
-					+ message.get(REQUEST_URL) + " to GET");
-			message.put(HTTP_REQUEST_METHOD, "GET");
-		}
-	}
-
-	/*
-	 * Stolen from http://permalink.gmane.org/gmane.comp.apache.cxf.user/20037
-	 * which is itself in turn stolen from
-	 * org.apache.cxf.frontend.WSDLGetInterceptor.isRecognizedQuery
-	 */
-	/**
-	 * Is this a query for WSDL or XSD relating to it?
-	 * 
-	 * @param query
-	 *            The query string to check
-	 * @return If the query is one to handle.
-	 * @see org.apache.cxf.frontend.WSDLGetInterceptor#isRecognizedQuery(Map,String,String,org.apache.cxf.service.model.EndpointInfo)
-	 *      WSDLGetInterceptor
-	 */
-	private boolean isRecognizedQuery(String query) {
-		Map<String, String> map = parseQueryString(query);
-		return map.containsKey("wsdl") || map.containsKey("xsd");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java
deleted file mode 100644
index 24246b5..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static java.lang.Thread.currentThread;
-import static java.sql.DriverManager.deregisterDriver;
-import static java.sql.DriverManager.getDrivers;
-import static org.taverna.server.master.utils.Contextualizer.ROOT_PLACEHOLDER;
-
-import java.io.PrintWriter;
-import java.sql.Connection;
-import java.sql.Driver;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.Enumeration;
-
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.dbcp.BasicDataSource;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-
-/**
- * Add some awareness of the context so that we can locate databases internally
- * to the webapp.
- * 
- * @author Donal Fellows
- */
-public class WebappAwareDataSource extends BasicDataSource {
-	Log log = LogFactory.getLog("Taverna.Server.Utils");
-	private transient boolean init;
-	private Contextualizer ctxt;
-	private String shutdownUrl;
-
-	@Required
-	public void setContextualizer(Contextualizer ctxt) {
-		this.ctxt = ctxt;
-	}
-
-	/**
-	 * A JDBC connection URL to use on shutting down the database. If not set,
-	 * do nothing special.
-	 * 
-	 * @param url
-	 */
-	public void setShutdownUrl(String url) {
-		shutdownUrl = url;
-	}
-
-	private void doInit() {
-		synchronized (this) {
-			if (!init) {
-				setDriverClassLoader(currentThread().getContextClassLoader());
-				String url = getUrl();
-				if (url.contains(ROOT_PLACEHOLDER)) {
-					String newurl = ctxt.contextualize(url);
-					setUrl(newurl);
-					log.info("mapped " + url + " to " + newurl);
-				} else {
-					log.info("did not find " + ROOT_PLACEHOLDER + " in " + url);
-				}
-				init = true;
-			}
-		}
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=- HOOKS -=-=-=-=-=-=-=-=-=-=-
-
-	@Override
-	public Connection getConnection() throws SQLException {
-		doInit();
-		return super.getConnection();
-	}
-
-	@Override
-	public void setLogWriter(PrintWriter pw) throws SQLException {
-		doInit();
-		super.setLogWriter(pw);
-	}
-
-	@Override
-	public void setLoginTimeout(int num) throws SQLException {
-		doInit();
-		super.setLoginTimeout(num);
-	}
-
-	@Override
-	public PrintWriter getLogWriter() throws SQLException {
-		doInit();
-		return super.getLogWriter();
-	}
-
-	@Override
-	public int getLoginTimeout() throws SQLException {
-		doInit();
-		return super.getLoginTimeout();
-	}
-
-	@PreDestroy
-	void realClose() {
-		try {
-			close();
-		} catch (SQLException e) {
-			log.warn("problem shutting down DB connection", e);
-		}
-		try {
-			if (shutdownUrl != null)
-				DriverManager.getConnection(ctxt.contextualize(shutdownUrl));
-		} catch (SQLException e) {
-			// Expected; ignore it
-		}
-		log = null;
-		dropDriver();
-	}
-
-	private void dropDriver() {
-		Enumeration<Driver> drivers = getDrivers();
-		while (drivers.hasMoreElements()) {
-			Driver d = drivers.nextElement();
-			if (d.getClass().getClassLoader() == getDriverClassLoader()
-					&& d.getClass().getName().equals(getDriverClassName())) {
-				try {
-					deregisterDriver(d);
-				} catch (SQLException e) {
-				}
-				break;
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java
deleted file mode 100644
index d258079..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static javax.security.auth.x500.X500Principal.RFC2253;
-
-import java.math.BigInteger;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.PreDestroy;
-import javax.security.auth.x500.X500Principal;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Support class that factors out some of the messier parts of working with
- * X.500 identities and X.509 certificates.
- * 
- * @author Donal Fellows
- */
-public class X500Utils {
-	private Log log = LogFactory.getLog("Taverna.Server.Utils");
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	private static final char DN_SEPARATOR = ',';
-	private static final char DN_ESCAPE = '\\';
-	private static final char DN_QUOTE = '"';
-
-	/**
-	 * Parse the DN from the Principal and extract the CN field.
-	 * 
-	 * @param id
-	 *            The identity to extract the distinguished name from.
-	 * @param fields
-	 *            The names to look at when finding the field to return. Each
-	 *            should be an upper-cased string.
-	 * @return The common-name part of the distinguished name, or the literal
-	 *         string "<tt>none</tt>" if there is no CN.
-	 */
-	public String getName(X500Principal id, String... fields) {
-		String dn = id.getName(RFC2253);
-
-		int i = 0;
-		int startIndex = 0;
-		boolean ignoreThisChar = false;
-		boolean inQuotes = false;
-		Map<String, String> tokenized = new HashMap<>();
-
-		for (i = 0; i < dn.length(); i++)
-			if (ignoreThisChar)
-				ignoreThisChar = false;
-			else if (dn.charAt(i) == DN_QUOTE)
-				inQuotes = !inQuotes;
-			else if (inQuotes)
-				continue;
-			else if (dn.charAt(i) == DN_ESCAPE)
-				ignoreThisChar = true;
-			else if ((dn.charAt(i) == DN_SEPARATOR) && !ignoreThisChar) {
-				storeDNField(tokenized, dn.substring(startIndex, i).trim()
-						.split("=", 2));
-				startIndex = i + 1;
-			}
-		if (inQuotes || ignoreThisChar)
-			log.warn("was parsing invalid DN format");
-		// Add last token - after the last delimiter
-		storeDNField(tokenized, dn.substring(startIndex).trim().split("=", 2));
-
-		for (String field : fields) {
-			String value = tokenized.get(field);
-			if (value != null)
-				return value;
-		}
-		return "none";
-	}
-
-	private void storeDNField(Map<String, String> container, String[] split) {
-		if (split == null || split.length != 2)
-			return;
-		String key = split[0].toUpperCase();
-		if (container.containsKey(key))
-			log.warn("duplicate field in DN: " + key);
-		// LATER: Should the field be de-quoted?
-		container.put(key, split[1]);
-	}
-
-	/**
-	 * Get the serial number from a certificate as a hex string.
-	 * 
-	 * @param cert
-	 *            The certificate to extract from.
-	 * @return A hex string, in upper-case.
-	 */
-	public String getSerial(X509Certificate cert) {
-		return new BigInteger(1, cert.getSerialNumber().toByteArray())
-				.toString(16).toUpperCase();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java
deleted file mode 100644
index 64a9f68..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-/**
- * Miscellaneous utility classes. Includes aspects that might be attached
- * for purposes such as transaction management and invocation tracking.
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java
deleted file mode 100644
index 1868f94..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-
-/**
- * How to convert a notification about the completion of a job into a message.
- * 
- * @author Donal Fellows
- */
-public interface CompletionNotifier {
-	/**
-	 * @return The name of this notifier.
-	 */
-	String getName();
-
-	/**
-	 * Called to get the content of a message that a workflow run has finished.
-	 * 
-	 * @param name
-	 *            The name of the run.
-	 * @param run
-	 *            What run are we talking about.
-	 * @param code
-	 *            What the exit code was.
-	 * @return The plain-text content of the message.
-	 */
-	String makeCompletionMessage(String name, RemoteRunDelegate run, int code);
-
-	/**
-	 * Called to get the subject of the message to dispatch.
-	 * 
-	 * @param name
-	 *            The name of the run.
-	 * @param run
-	 *            What run are we talking about.
-	 * @param code
-	 *            What the exit code was.
-	 * @return The plain-text subject of the message.
-	 */
-	String makeMessageSubject(String name, RemoteRunDelegate run, int code);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java
deleted file mode 100644
index d38f0cc..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import org.taverna.server.master.notification.atom.EventDAO;
-
-/**
- * What the remote run really needs of its factory.
- * 
- * @author Donal Fellows
- */
-public interface FactoryBean {
-	/**
-	 * @return Whether a run can actually be started at this time.
-	 */
-	boolean isAllowingRunsToStart();
-
-	/**
-	 * @return a handle to the master Atom event feed (<i>not</i> the per-run
-	 *         feed)
-	 */
-	EventDAO getMasterEventFeed();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java
deleted file mode 100644
index 649db64..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * A simple password issuing bean.
- * 
- * @author Donal Fellows
- */
-public class PasswordIssuer {
-	private static final char[] ALPHABET = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
-			'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
-			'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
-			'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
-			'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7',
-			'8', '9', '0', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
-			',', '.', '<', '>', '/', '?', ':', ';', '-', '_', '+', '[', ']',
-			'{', '}', '`', '~' };
-	private Log log = LogFactory.getLog("Taverna.Server.Worker");
-	private SecureRandom r;
-	private int length;
-
-	public PasswordIssuer() {
-		r = new SecureRandom();
-		log.info("constructing passwords with " + r.getAlgorithm());
-		setLength(8);
-	}
-
-	public PasswordIssuer(String algorithm) throws NoSuchAlgorithmException {
-		r = SecureRandom.getInstance(algorithm);
-		log.info("constructing passwords with " + r.getAlgorithm());
-		setLength(8);
-	}
-
-	public void setLength(int length) {
-		this.length = length;
-		log.info("issued password will be " + this.length
-				+ " symbols chosen from " + ALPHABET.length);
-	}
-
-	/**
-	 * Issue a password.
-	 * 
-	 * @return The new password.
-	 */
-	public String issue() {
-		StringBuilder sb = new StringBuilder();
-		for (int i = 0; i < length; i++)
-			sb.append(ALPHABET[r.nextInt(ALPHABET.length)]);
-		log.info("issued new password of length " + sb.length());
-		return sb.toString();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java
deleted file mode 100644
index 37d5760..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
-
-import java.net.URI;
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.taverna.server.master.common.Roles;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Basic policy implementation that allows any workflow to be instantiated by
- * any user, but which does not permit users to access each others workflow
- * runs. It also imposes a global limit on the number of workflow runs at once.
- * 
- * @author Donal Fellows
- */
-class PolicyImpl implements Policy {
-	Log log = LogFactory.getLog("Taverna.Server.Worker.Policy");
-	private PolicyLimits limits;
-	private RunDBSupport runDB;
-
-	@Required
-	public void setLimits(PolicyLimits limits) {
-		this.limits = limits;
-	}
-
-	@Required
-	public void setRunDB(RunDBSupport runDB) {
-		this.runDB = runDB;
-	}
-
-	@Override
-	public int getMaxRuns() {
-		return limits.getMaxRuns();
-	}
-
-	@Override
-	public Integer getMaxRuns(UsernamePrincipal user) {
-		return null;
-	}
-
-	@Override
-	public int getOperatingLimit() {
-		return limits.getOperatingLimit();
-	}
-
-	@Override
-	public List<URI> listPermittedWorkflowURIs(UsernamePrincipal user) {
-		return limits.getPermittedWorkflowURIs();
-	}
-
-	private boolean isSelfAccess(String runId) {
-		Authentication auth = SecurityContextHolder.getContext()
-				.getAuthentication();
-		boolean self = false;
-		String id = null;
-		for (GrantedAuthority a : auth.getAuthorities()) {
-			String aa = a.getAuthority();
-			if (aa.equals(Roles.SELF)) {
-				self = true;
-				continue;
-			}
-			if (!aa.startsWith(PREFIX))
-				continue;
-			id = aa.substring(PREFIX.length());
-		}
-		return self && runId.equals(id);
-	}
-
-	@Override
-	public boolean permitAccess(UsernamePrincipal user, TavernaRun run) {
-		String username = user.getName();
-		TavernaSecurityContext context = run.getSecurityContext();
-		if (context.getOwner().getName().equals(username)) {
-			if (log.isDebugEnabled())
-				log.debug("granted access by " + user.getName() + " to "
-						+ run.getId());
-			return true;
-		}
-		if (isSelfAccess(run.getId())) {
-			if (log.isDebugEnabled())
-				log.debug("access by workflow to itself: " + run.getId());
-			return true;
-		}
-		if (log.isDebugEnabled())
-			log.debug("considering access by " + user.getName() + " to "
-					+ run.getId());
-		return context.getPermittedReaders().contains(username);
-	}
-
-	@Override
-	public void permitCreate(UsernamePrincipal user, Workflow workflow)
-			throws NoCreateException {
-		if (user == null)
-			throw new NoCreateException(
-					"anonymous workflow creation not allowed");
-		if (runDB.countRuns() >= getMaxRuns())
-			throw new NoCreateException("server load exceeded; please wait");
-	}
-
-	@Override
-	public synchronized void permitDestroy(UsernamePrincipal user, TavernaRun run)
-			throws NoDestroyException {
-		if (user == null)
-			throw new NoDestroyException();
-		String username = user.getName();
-		TavernaSecurityContext context = run.getSecurityContext();
-		if (context.getOwner() == null
-				|| context.getOwner().getName().equals(username))
-			return;
-		if (!context.getPermittedDestroyers().contains(username))
-			throw new NoDestroyException();
-	}
-
-	@Override
-	public void permitUpdate(UsernamePrincipal user, TavernaRun run)
-			throws NoUpdateException {
-		if (user == null)
-			throw new NoUpdateException(
-					"workflow run not owned by you and you're not granted access");
-		TavernaSecurityContext context = run.getSecurityContext();
-		if (context.getOwner().getName().equals(user.getName()))
-			return;
-		if (isSelfAccess(run.getId())) {
-			if (log.isDebugEnabled())
-				log.debug("update access by workflow to itself: " + run.getId());
-			return;
-		}
-		if (!context.getPermittedUpdaters().contains(user.getName()))
-			throw new NoUpdateException(
-					"workflow run not owned by you and you're not granted access");
-	}
-
-	@Override
-	public void setPermittedWorkflowURIs(UsernamePrincipal user,
-			List<URI> permitted) {
-		limits.setPermittedWorkflowURIs(permitted);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java
deleted file mode 100644
index 43c0aa4..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import java.net.URI;
-import java.util.List;
-
-import org.taverna.server.master.common.Status;
-
-/**
- * The worker policy delegates certain limits to the state model of the
- * particular worker.
- * 
- * @author Donal Fellows
- */
-public interface PolicyLimits {
-	/**
-	 * @return the maximum number of extant workflow runs in any state
-	 */
-	int getMaxRuns();
-
-	/**
-	 * @return the maximum number of workflow runs in the
-	 *         {@linkplain Status#Operating operating} state.
-	 */
-	int getOperatingLimit();
-
-	/**
-	 * @return the list of URIs to workflows that may be used to create workflow
-	 *         runs. If empty or <tt>null</tt>, no restriction is present.
-	 */
-	List<URI> getPermittedWorkflowURIs();
-
-	/**
-	 * @param permitted
-	 *            the list of URIs to workflows that may be used to create
-	 *            workflow runs.
-	 */
-	void setPermittedWorkflowURIs(List<URI> permitted);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java
deleted file mode 100644
index fb1ac47..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static java.lang.System.currentTimeMillis;
-import static java.util.Calendar.MINUTE;
-import static java.util.Collections.sort;
-import static java.util.Collections.unmodifiableSet;
-import static java.util.UUID.randomUUID;
-import static org.apache.commons.io.IOUtils.closeQuietly;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.worker.RemoteRunDelegate.checkBadFilename;
-import static org.taverna.server.master.worker.RunConnection.NAME_LENGTH;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.PipedOutputStream;
-import java.rmi.MarshalledObject;
-import java.rmi.RemoteException;
-import java.security.GeneralSecurityException;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-
-import javax.annotation.Nonnull;
-
-import org.apache.commons.logging.Log;
-import org.taverna.server.localworker.remote.IllegalStateTransitionException;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
-import org.taverna.server.localworker.remote.RemoteFile;
-import org.taverna.server.localworker.remote.RemoteInput;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.remote.StillWorkingOnItException;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.OverloadedException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Bridging shim between the WebApp world and the RMI world.
- * 
- * @author Donal Fellows
- */
-@SuppressWarnings("serial")
-public class RemoteRunDelegate implements TavernaRun {
-	private transient Log log = getLog("Taverna.Server.Worker");
-	transient TavernaSecurityContext secContext;
-	Date creationInstant;
-	Workflow workflow;
-	Date expiry;
-	HashSet<String> readers;
-	HashSet<String> writers;
-	HashSet<String> destroyers;
-	transient String id;
-	transient RemoteSingleRun run;
-	transient RunDBSupport db;
-	transient FactoryBean factory;
-	boolean doneTransitionToFinished;
-	boolean generateProvenance;// FIXME expose
-	String name;
-	private static final String ELLIPSIS = "...";
-
-	public RemoteRunDelegate(Date creationInstant, Workflow workflow,
-			RemoteSingleRun rsr, int defaultLifetime, RunDBSupport db, UUID id,
-			boolean generateProvenance, FactoryBean factory) {
-		if (rsr == null)
-			throw new IllegalArgumentException("remote run must not be null");
-		this.creationInstant = creationInstant;
-		this.workflow = workflow;
-		Calendar c = Calendar.getInstance();
-		c.add(MINUTE, defaultLifetime);
-		this.expiry = c.getTime();
-		this.run = rsr;
-		this.db = db;
-		this.generateProvenance = generateProvenance;
-		this.factory = factory;
-		try {
-			this.name = "";
-			String ci = " " + creationInstant;
-			String n = workflow.getName();
-			if (n.length() > NAME_LENGTH - ci.length())
-				n = n.substring(0,
-						NAME_LENGTH - ci.length() - ELLIPSIS.length())
-						+ ELLIPSIS;
-			this.name = n + ci;
-		} catch (Exception e) {
-			// Ignore; it's just a name, not something important.
-		}
-		if (id != null)
-			this.id = id.toString();
-	}
-
-	RemoteRunDelegate() {
-	}
-
-	/**
-	 * Get the types of listener supported by this run.
-	 * 
-	 * @return A list of listener type names.
-	 * @throws RemoteException
-	 *             If anything goes wrong.
-	 */
-	public List<String> getListenerTypes() throws RemoteException {
-		return run.getListenerTypes();
-	}
-
-	@Override
-	public void addListener(Listener listener) {
-		if (listener instanceof ListenerDelegate)
-			try {
-				run.addListener(((ListenerDelegate) listener).getRemote());
-			} catch (RemoteException e) {
-				log.warn("communication problem adding listener", e);
-			} catch (ImplementationException e) {
-				log.warn("implementation problem adding listener", e);
-			}
-		else
-			log.fatal("bad listener " + listener.getClass()
-					+ "; not applicable remotely!");
-	}
-
-	@Override
-	public String getId() {
-		if (id == null)
-			id = randomUUID().toString();
-		return id;
-	}
-
-	/**
-	 * Attach a listener to a workflow run and return its local delegate.
-	 * 
-	 * @param type
-	 *            The type of listener to create.
-	 * @param config
-	 *            The configuration of the listener.
-	 * @return The local delegate of the listener.
-	 * @throws NoListenerException
-	 *             If anything goes wrong.
-	 */
-	public Listener makeListener(String type, String config)
-			throws NoListenerException {
-		try {
-			return new ListenerDelegate(run.makeListener(type, config));
-		} catch (RemoteException e) {
-			throw new NoListenerException("failed to make listener", e);
-		}
-	}
-
-	@Override
-	public void destroy() {
-		try {
-			run.destroy();
-		} catch (RemoteException | ImplementationException e) {
-			log.warn("failed to destroy run", e);
-		}
-	}
-
-	@Override
-	public Date getExpiry() {
-		return new Date(expiry.getTime());
-	}
-
-	@Override
-	public List<Listener> getListeners() {
-		List<Listener> listeners = new ArrayList<>();
-		try {
-			for (RemoteListener rl : run.getListeners())
-				listeners.add(new ListenerDelegate(rl));
-		} catch (RemoteException e) {
-			log.warn("failed to get listeners", e);
-		}
-		return listeners;
-	}
-
-	@Override
-	public TavernaSecurityContext getSecurityContext() {
-		return secContext;
-	}
-
-	@Override
-	public Status getStatus() {
-		try {
-			switch (run.getStatus()) {
-			case Initialized:
-				return Status.Initialized;
-			case Operating:
-				return Status.Operating;
-			case Stopped:
-				return Status.Stopped;
-			case Finished:
-				return Status.Finished;
-			}
-		} catch (RemoteException e) {
-			log.warn("problem getting remote status", e);
-		}
-		return Status.Finished;
-	}
-
-	@Override
-	public Workflow getWorkflow() {
-		return workflow;
-	}
-
-	@Override
-	public Directory getWorkingDirectory() throws FilesystemAccessException {
-		try {
-			return new DirectoryDelegate(run.getWorkingDirectory());
-		} catch (Throwable e) {
-			if (e.getCause() != null)
-				e = e.getCause();
-			throw new FilesystemAccessException(
-					"problem getting main working directory handle", e);
-		}
-	}
-
-	@Override
-	public void setExpiry(Date d) {
-		if (d.after(new Date()))
-			expiry = new Date(d.getTime());
-		db.flushToDisk(this);
-	}
-
-	@Override
-	public String setStatus(Status s) throws BadStateChangeException {
-		try {
-			log.info("setting status of run " + id + " to " + s);
-			switch (s) {
-			case Initialized:
-				run.setStatus(RemoteStatus.Initialized);
-				break;
-			case Operating:
-				if (run.getStatus() == RemoteStatus.Initialized) {
-					if (!factory.isAllowingRunsToStart())
-						throw new OverloadedException();
-					secContext.conveySecurity();
-				}
-				run.setGenerateProvenance(generateProvenance);
-				run.setStatus(RemoteStatus.Operating);
-				factory.getMasterEventFeed()
-						.started(
-								this,
-								"started run execution",
-								"The execution of run '" + getName()
-										+ "' has started.");
-				break;
-			case Stopped:
-				run.setStatus(RemoteStatus.Stopped);
-				break;
-			case Finished:
-				run.setStatus(RemoteStatus.Finished);
-				break;
-			}
-			return null;
-		} catch (IllegalStateTransitionException e) {
-			throw new BadStateChangeException(e.getMessage());
-		} catch (RemoteException e) {
-			throw new BadStateChangeException(e.getMessage(), e.getCause());
-		} catch (GeneralSecurityException | IOException e) {
-			throw new BadStateChangeException(e.getMessage(), e);
-		} catch (ImplementationException e) {
-			if (e.getCause() != null)
-				throw new BadStateChangeException(e.getMessage(), e.getCause());
-			throw new BadStateChangeException(e.getMessage(), e);
-		} catch (StillWorkingOnItException e) {
-			log.info("still working on setting status of run " + id + " to "
-					+ s, e);
-			return e.getMessage();
-		} catch (InterruptedException e) {
-			throw new BadStateChangeException(
-					"interrupted while waiting to insert notification into database");
-		}
-	}
-
-	static void checkBadFilename(String filename)
-			throws FilesystemAccessException {
-		if (filename.startsWith("/"))
-			throw new FilesystemAccessException("filename may not be absolute");
-		if (Arrays.asList(filename.split("/")).contains(".."))
-			throw new FilesystemAccessException(
-					"filename may not refer to parent");
-	}
-
-	@Override
-	public String getInputBaclavaFile() {
-		try {
-			return run.getInputBaclavaFile();
-		} catch (RemoteException e) {
-			log.warn("problem when fetching input baclava file", e);
-			return null;
-		}
-	}
-
-	@Override
-	public List<Input> getInputs() {
-		ArrayList<Input> inputs = new ArrayList<>();
-		try {
-			for (RemoteInput ri : run.getInputs())
-				inputs.add(new RunInput(ri));
-		} catch (RemoteException e) {
-			log.warn("problem when fetching list of workflow inputs", e);
-		}
-		return inputs;
-	}
-
-	@Override
-	public String getOutputBaclavaFile() {
-		try {
-			return run.getOutputBaclavaFile();
-		} catch (RemoteException e) {
-			log.warn("problem when fetching output baclava file", e);
-			return null;
-		}
-	}
-
-	@Override
-	public Input makeInput(String name) throws BadStateChangeException {
-		try {
-			return new RunInput(run.makeInput(name));
-		} catch (RemoteException e) {
-			throw new BadStateChangeException("failed to make input", e);
-		}
-	}
-
-	@Override
-	public void setInputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException {
-		checkBadFilename(filename);
-		try {
-			run.setInputBaclavaFile(filename);
-		} catch (RemoteException e) {
-			throw new FilesystemAccessException(
-					"cannot set input baclava file name", e);
-		}
-	}
-
-	@Override
-	public void setOutputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException {
-		checkBadFilename(filename);
-		try {
-			run.setOutputBaclavaFile(filename);
-		} catch (RemoteException e) {
-			throw new FilesystemAccessException(
-					"cannot set output baclava file name", e);
-		}
-	}
-
-	@Override
-	public Date getCreationTimestamp() {
-		return creationInstant == null ? null : new Date(
-				creationInstant.getTime());
-	}
-
-	@Override
-	public Date getFinishTimestamp() {
-		try {
-			return run.getFinishTimestamp();
-		} catch (RemoteException e) {
-			log.info("failed to get finish timestamp", e);
-			return null;
-		}
-	}
-
-	@Override
-	public Date getStartTimestamp() {
-		try {
-			return run.getStartTimestamp();
-		} catch (RemoteException e) {
-			log.info("failed to get finish timestamp", e);
-			return null;
-		}
-	}
-
-	/**
-	 * @param readers
-	 *            the readers to set
-	 */
-	public void setReaders(Set<String> readers) {
-		this.readers = new HashSet<>(readers);
-		db.flushToDisk(this);
-	}
-
-	/**
-	 * @return the readers
-	 */
-	public Set<String> getReaders() {
-		return readers == null ? new HashSet<String>()
-				: unmodifiableSet(readers);
-	}
-
-	/**
-	 * @param writers
-	 *            the writers to set
-	 */
-	public void setWriters(Set<String> writers) {
-		this.writers = new HashSet<>(writers);
-		db.flushToDisk(this);
-	}
-
-	/**
-	 * @return the writers
-	 */
-	public Set<String> getWriters() {
-		return writers == null ? new HashSet<String>()
-				: unmodifiableSet(writers);
-	}
-
-	/**
-	 * @param destroyers
-	 *            the destroyers to set
-	 */
-	public void setDestroyers(Set<String> destroyers) {
-		this.destroyers = new HashSet<>(destroyers);
-		db.flushToDisk(this);
-	}
-
-	/**
-	 * @return the destroyers
-	 */
-	public Set<String> getDestroyers() {
-		return destroyers == null ? new HashSet<String>()
-				: unmodifiableSet(destroyers);
-	}
-
-	private void writeObject(ObjectOutputStream out) throws IOException {
-		out.defaultWriteObject();
-		out.writeUTF(secContext.getOwner().getName());
-		out.writeObject(secContext.getFactory());
-		out.writeObject(new MarshalledObject<>(run));
-	}
-
-	@Override
-	public boolean getGenerateProvenance() {
-		return generateProvenance;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean generateProvenance) {
-		this.generateProvenance = generateProvenance;
-		db.flushToDisk(this);
-	}
-
-	@SuppressWarnings("unchecked")
-	private void readObject(ObjectInputStream in) throws IOException,
-			ClassNotFoundException {
-		in.defaultReadObject();
-		if (log == null)
-			log = getLog("Taverna.Server.LocalWorker");
-		final String creatorName = in.readUTF();
-		SecurityContextFactory factory = (SecurityContextFactory) in
-				.readObject();
-		try {
-			secContext = factory.create(this,
-					new UsernamePrincipal(creatorName));
-		} catch (RuntimeException | IOException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new SecurityContextReconstructionException(e);
-		}
-		run = ((MarshalledObject<RemoteSingleRun>) in.readObject()).get();
-	}
-
-	public void setSecurityContext(TavernaSecurityContext tavernaSecurityContext) {
-		secContext = tavernaSecurityContext;
-	}
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	@Override
-	public void setName(@Nonnull String name) {
-		if (name.length() > RunConnection.NAME_LENGTH)
-			this.name = name.substring(0, RunConnection.NAME_LENGTH);
-		else
-			this.name = name;
-		db.flushToDisk(this);
-	}
-
-	@Override
-	public void ping() throws UnknownRunException {
-		try {
-			run.ping();
-		} catch (RemoteException e) {
-			throw new UnknownRunException(e);
-		}
-	}
-}
-
-abstract class DEDelegate implements DirectoryEntry {
-	Log log = getLog("Taverna.Server.Worker");
-	private RemoteDirectoryEntry entry;
-	private String name;
-	private String full;
-	private Date cacheModTime;
-	private long cacheQueryTime = 0L;
-
-	DEDelegate(RemoteDirectoryEntry entry) {
-		this.entry = entry;
-	}
-
-	@Override
-	public void destroy() throws FilesystemAccessException {
-		try {
-			entry.destroy();
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"failed to delete directory entry", e);
-		}
-	}
-
-	@Override
-	public String getFullName() {
-		if (full != null)
-			return full;
-		String n = getName();
-		RemoteDirectoryEntry re = entry;
-		try {
-			while (true) {
-				RemoteDirectory parent = re.getContainingDirectory();
-				if (parent == null)
-					break;
-				n = parent.getName() + "/" + n;
-				re = parent;
-			}
-		} catch (RemoteException e) {
-			log.warn("failed to generate full name", e);
-		}
-		return (full = n);
-	}
-
-	@Override
-	public String getName() {
-		if (name == null)
-			try {
-				name = entry.getName();
-			} catch (RemoteException e) {
-				log.error("failed to get name", e);
-			}
-		return name;
-	}
-
-	@Override
-	public Date getModificationDate() {
-		if (cacheModTime == null || currentTimeMillis() - cacheQueryTime < 5000)
-			try {
-				cacheModTime = entry.getModificationDate();
-				cacheQueryTime = currentTimeMillis();
-			} catch (RemoteException e) {
-				log.error("failed to get modification time", e);
-			}
-		return cacheModTime;
-	}
-
-	@Override
-	public int compareTo(DirectoryEntry de) {
-		return getFullName().compareTo(de.getFullName());
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		return o != null && o instanceof DEDelegate
-				&& getFullName().equals(((DEDelegate) o).getFullName());
-	}
-
-	@Override
-	public int hashCode() {
-		return getFullName().hashCode();
-	}
-}
-
-class DirectoryDelegate extends DEDelegate implements Directory {
-	RemoteDirectory rd;
-
-	DirectoryDelegate(RemoteDirectory dir) {
-		super(dir);
-		rd = dir;
-	}
-
-	@Override
-	public Collection<DirectoryEntry> getContents()
-			throws FilesystemAccessException {
-		ArrayList<DirectoryEntry> result = new ArrayList<>();
-		try {
-			for (RemoteDirectoryEntry rde : rd.getContents()) {
-				if (rde instanceof RemoteDirectory)
-					result.add(new DirectoryDelegate((RemoteDirectory) rde));
-				else
-					result.add(new FileDelegate((RemoteFile) rde));
-			}
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"failed to get directory contents", e);
-		}
-		return result;
-	}
-
-	@Override
-	public Collection<DirectoryEntry> getContentsByDate()
-			throws FilesystemAccessException {
-		ArrayList<DirectoryEntry> result = new ArrayList<>(getContents());
-		sort(result, new DateComparator());
-		return result;
-	}
-
-	static class DateComparator implements Comparator<DirectoryEntry> {
-		@Override
-		public int compare(DirectoryEntry a, DirectoryEntry b) {
-			return a.getModificationDate().compareTo(b.getModificationDate());
-		}
-	}
-
-	@Override
-	public File makeEmptyFile(Principal actor, String name)
-			throws FilesystemAccessException {
-		try {
-			return new FileDelegate(rd.makeEmptyFile(name));
-		} catch (IOException e) {
-			throw new FilesystemAccessException("failed to make empty file", e);
-		}
-	}
-
-	@Override
-	public Directory makeSubdirectory(Principal actor, String name)
-			throws FilesystemAccessException {
-		try {
-			return new DirectoryDelegate(rd.makeSubdirectory(name));
-		} catch (IOException e) {
-			throw new FilesystemAccessException("failed to make subdirectory",
-					e);
-		}
-	}
-
-	@Override
-	public ZipStream getContentsAsZip() throws FilesystemAccessException {
-		ZipStream zs = new ZipStream();
-
-		final ZipOutputStream zos;
-		try {
-			zos = new ZipOutputStream(new PipedOutputStream(zs));
-		} catch (IOException e) {
-			throw new FilesystemAccessException("problem building zip stream",
-					e);
-		}
-		Thread t = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					zipDirectory(rd, null, zos);
-				} catch (IOException e) {
-					log.warn("problem when zipping directory", e);
-				} finally {
-					closeQuietly(zos);
-				}
-			}
-		});
-		t.setDaemon(true);
-		t.start();
-		return zs;
-	}
-
-	/**
-	 * Compresses a directory tree into a ZIP.
-	 * 
-	 * @param dir
-	 *            The directory to compress.
-	 * @param base
-	 *            The base name of the directory (or <tt>null</tt> if this is
-	 *            the root directory of the ZIP).
-	 * @param zos
-	 *            Where to write the compressed data.
-	 * @throws RemoteException
-	 *             If some kind of problem happens with the remote delegates.
-	 * @throws IOException
-	 *             If we run into problems with reading or writing data.
-	 */
-	void zipDirectory(RemoteDirectory dir, String base, ZipOutputStream zos)
-			throws RemoteException, IOException {
-		for (RemoteDirectoryEntry rde : dir.getContents()) {
-			String name = rde.getName();
-			if (base != null)
-				name = base + "/" + name;
-			if (rde instanceof RemoteDirectory) {
-				RemoteDirectory rd = (RemoteDirectory) rde;
-				zipDirectory(rd, name, zos);
-			} else {
-				RemoteFile rf = (RemoteFile) rde;
-				zos.putNextEntry(new ZipEntry(name));
-				try {
-					int off = 0;
-					while (true) {
-						byte[] c = rf.getContents(off, 64 * 1024);
-						if (c == null || c.length == 0)
-							break;
-						zos.write(c);
-						off += c.length;
-					}
-				} finally {
-					zos.closeEntry();
-				}
-			}
-		}
-	}
-}
-
-class FileDelegate extends DEDelegate implements File {
-	RemoteFile rf;
-
-	FileDelegate(RemoteFile f) {
-		super(f);
-		this.rf = f;
-	}
-
-	@Override
-	public byte[] getContents(int offset, int length)
-			throws FilesystemAccessException {
-		try {
-			return rf.getContents(offset, length);
-		} catch (IOException e) {
-			throw new FilesystemAccessException("failed to read file contents",
-					e);
-		}
-	}
-
-	@Override
-	public long getSize() throws FilesystemAccessException {
-		try {
-			return rf.getSize();
-		} catch (IOException e) {
-			throw new FilesystemAccessException("failed to get file length", e);
-		}
-	}
-
-	@Override
-	public void setContents(byte[] data) throws FilesystemAccessException {
-		try {
-			rf.setContents(data);
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"failed to write file contents", e);
-		}
-	}
-
-	@Override
-	public void appendContents(byte[] data) throws FilesystemAccessException {
-		try {
-			rf.appendContents(data);
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"failed to write file contents", e);
-		}
-	}
-
-	@Override
-	public void copy(File from) throws FilesystemAccessException {
-		FileDelegate fromFile;
-		try {
-			fromFile = (FileDelegate) from;
-		} catch (ClassCastException e) {
-			throw new FilesystemAccessException("different types of File?!");
-		}
-
-		try {
-			rf.copy(fromFile.rf);
-		} catch (Exception e) {
-			throw new FilesystemAccessException("failed to copy file contents",
-					e);
-		}
-		return;
-	}
-}
-
-class ListenerDelegate implements Listener {
-	private Log log = getLog("Taverna.Server.Worker");
-	private RemoteListener r;
-	String conf;
-
-	ListenerDelegate(RemoteListener l) {
-		r = l;
-	}
-
-	RemoteListener getRemote() {
-		return r;
-	}
-
-	@Override
-	public String getConfiguration() {
-		try {
-			if (conf == null)
-				conf = r.getConfiguration();
-		} catch (RemoteException e) {
-			log.warn("failed to get configuration", e);
-		}
-		return conf;
-	}
-
-	@Override
-	public String getName() {
-		try {
-			return r.getName();
-		} catch (RemoteException e) {
-			log.warn("failed to get name", e);
-			return "UNKNOWN NAME";
-		}
-	}
-
-	@Override
-	public String getProperty(String propName) throws NoListenerException {
-		try {
-			return r.getProperty(propName);
-		} catch (RemoteException e) {
-			throw new NoListenerException("no such property: " + propName, e);
-		}
-	}
-
-	@Override
-	public String getType() {
-		try {
-			return r.getType();
-		} catch (RemoteException e) {
-			log.warn("failed to get type", e);
-			return "UNKNOWN TYPE";
-		}
-	}
-
-	@Override
-	public String[] listProperties() {
-		try {
-			return r.listProperties();
-		} catch (RemoteException e) {
-			log.warn("failed to list properties", e);
-			return new String[0];
-		}
-	}
-
-	@Override
-	public void setProperty(String propName, String value)
-			throws NoListenerException, BadPropertyValueException {
-		try {
-			r.setProperty(propName, value);
-		} catch (RemoteException e) {
-			log.warn("failed to set property", e);
-			if (e.getCause() != null
-					&& e.getCause() instanceof RuntimeException)
-				throw new NoListenerException("failed to set property",
-						e.getCause());
-			if (e.getCause() != null && e.getCause() instanceof Exception)
-				throw new BadPropertyValueException("failed to set property",
-						e.getCause());
-			throw new BadPropertyValueException("failed to set property", e);
-		}
-	}
-}
-
-class RunInput implements Input {
-	private final RemoteInput i;
-
-	RunInput(RemoteInput remote) {
-		this.i = remote;
-	}
-
-	@Override
-	public String getFile() {
-		try {
-			return i.getFile();
-		} catch (RemoteException e) {
-			return null;
-		}
-	}
-
-	@Override
-	public String getName() {
-		try {
-			return i.getName();
-		} catch (RemoteException e) {
-			return null;
-		}
-	}
-
-	@Override
-	public String getValue() {
-		try {
-			return i.getValue();
-		} catch (RemoteException e) {
-			return null;
-		}
-	}
-
-	@Override
-	public void setFile(String file) throws FilesystemAccessException,
-			BadStateChangeException {
-		checkBadFilename(file);
-		try {
-			i.setFile(file);
-		} catch (RemoteException e) {
-			throw new FilesystemAccessException("cannot set file for input", e);
-		}
-	}
-
-	@Override
-	public void setValue(String value) throws BadStateChangeException {
-		try {
-			i.setValue(value);
-		} catch (RemoteException e) {
-			throw new BadStateChangeException(e);
-		}
-	}
-
-	@Override
-	public String getDelimiter() {
-		try {
-			return i.getDelimiter();
-		} catch (RemoteException e) {
-			return null;
-		}
-	}
-
-	@Override
-	public void setDelimiter(String delimiter) throws BadStateChangeException {
-		try {
-			if (delimiter != null)
-				delimiter = delimiter.substring(0, 1);
-			i.setDelimiter(delimiter);
-		} catch (RemoteException e) {
-			throw new BadStateChangeException(e);
-		}
-	}
-}
-
-@SuppressWarnings("serial")
-class SecurityContextReconstructionException extends RuntimeException {
-	public SecurityContextReconstructionException(Throwable t) {
-		super("failed to rebuild security context", t);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java
deleted file mode 100644
index 0c2b1a9..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static org.taverna.server.master.worker.RunConnection.COUNT_QUERY;
-import static org.taverna.server.master.worker.RunConnection.NAMES_QUERY;
-import static org.taverna.server.master.worker.RunConnection.SCHEMA;
-import static org.taverna.server.master.worker.RunConnection.TABLE;
-import static org.taverna.server.master.worker.RunConnection.TIMEOUT_QUERY;
-import static org.taverna.server.master.worker.RunConnection.UNTERMINATED_QUERY;
-
-import java.io.IOException;
-import java.rmi.MarshalledObject;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.jdo.annotations.Column;
-import javax.jdo.annotations.Join;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.PrimaryKey;
-import javax.jdo.annotations.Queries;
-import javax.jdo.annotations.Query;
-
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * The representation of the connections to the runs that actually participates
- * in the persistence system.
- * 
- * @author Donal Fellows
- */
-@PersistenceCapable(table = TABLE, schema = SCHEMA)
-@Queries({
-		@Query(name = "count", language = "SQL", value = COUNT_QUERY, unique = "true", resultClass = Integer.class),
-		@Query(name = "names", language = "SQL", value = NAMES_QUERY, unique = "false", resultClass = String.class),
-		@Query(name = "unterminated", language = "SQL", value = UNTERMINATED_QUERY, unique = "false", resultClass = String.class),
-		@Query(name = "timedout", language = "SQL", value = TIMEOUT_QUERY, unique = "false", resultClass = String.class) })
-public class RunConnection {
-	static final String SCHEMA = "TAVERNA";
-	static final String TABLE = "RUN_CONNECTION";
-	private static final String FULL_NAME = SCHEMA + "." + TABLE;
-	static final String COUNT_QUERY = "SELECT count(*) FROM " + FULL_NAME;
-	static final String NAMES_QUERY = "SELECT ID FROM " + FULL_NAME;
-	static final String TIMEOUT_QUERY = "SELECT ID FROM " + FULL_NAME
-			+ "   WHERE expiry < CURRENT_TIMESTAMP";
-	static final String UNTERMINATED_QUERY = "SELECT ID FROM " + FULL_NAME
-			+ "   WHERE doneTransitionToFinished = 0";
-	static final int NAME_LENGTH = 48; 
-
-	@PrimaryKey
-	@Column(length = 40)
-	private String id;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Column(length = NAME_LENGTH)
-	private String name;
-
-	@Persistent(defaultFetchGroup = "true")
-	private Date creationInstant;
-
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private Workflow workflow;
-
-	@Persistent(defaultFetchGroup = "true")
-	private Date expiry;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Join(table = TABLE + "_READERS", column = "ID")
-	private String[] readers;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Join(table = TABLE + "_WRITERS", column = "ID")
-	private String[] writers;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Join(table = TABLE + "_DESTROYERS", column = "ID")
-	private String[] destroyers;
-
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private MarshalledObject<RemoteSingleRun> run;
-
-	@Persistent(defaultFetchGroup = "true")
-	private int doneTransitionToFinished;
-
-	@Persistent(defaultFetchGroup = "true")
-	private int generateProvenance;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Column(length = 128)
-	String owner;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Column(length = 36)
-	private String securityToken;
-
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private SecurityContextFactory securityContextFactory;
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private Credential[] credentials;
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private Trust[] trust;
-
-	private static final String[] STRING_ARY = new String[0];
-
-	public String getId() {
-		return id;
-	}
-
-	public boolean isFinished() {
-		return doneTransitionToFinished != 0;
-	}
-
-	public void setFinished(boolean finished) {
-		doneTransitionToFinished = (finished ? 1 : 0);
-	}
-
-	public boolean isProvenanceGenerated() {
-		return generateProvenance != 0;
-	}
-
-	public void setProvenanceGenerated(boolean generate) {
-		generateProvenance = (generate ? 1 : 0);
-	}
-
-	/**
-	 * Manufacture a persistent representation of the given workflow run. Must
-	 * be called within the context of a transaction.
-	 * 
-	 * @param rrd
-	 *            The remote delegate of the workflow run.
-	 * @return The persistent object.
-	 * @throws IOException
-	 *             If serialisation fails.
-	 */
-	@Nonnull
-	public static RunConnection toDBform(@Nonnull RemoteRunDelegate rrd)
-			throws IOException {
-		RunConnection rc = new RunConnection();
-		rc.id = rrd.id;
-		rc.makeChanges(rrd);
-		return rc;
-	}
-
-	private static List<String> list(String[] ary) {
-		if (ary == null)
-			return emptyList();
-		return asList(ary);
-	}
-
-	/**
-	 * Get the remote run delegate for a particular persistent connection. Must
-	 * be called within the context of a transaction.
-	 * 
-	 * @param db
-	 *            The database facade.
-	 * @return The delegate object.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	@Nonnull
-	public RemoteRunDelegate fromDBform(@Nonnull RunDBSupport db)
-			throws Exception {
-		RemoteRunDelegate rrd = new RemoteRunDelegate();
-		rrd.id = getId();
-		rrd.creationInstant = creationInstant;
-		rrd.workflow = workflow;
-		rrd.expiry = expiry;
-		rrd.readers = new HashSet<>(list(readers));
-		rrd.writers = new HashSet<>(list(writers));
-		rrd.destroyers = new HashSet<>(list(destroyers));
-		rrd.run = run.get();
-		rrd.doneTransitionToFinished = isFinished();
-		rrd.generateProvenance = isProvenanceGenerated();
-		rrd.secContext = securityContextFactory.create(rrd,
-				new UsernamePrincipal(owner));
-		((SecurityContextDelegate)rrd.secContext).setCredentialsAndTrust(credentials,trust);
-		rrd.db = db;
-		rrd.factory = db.getFactory();
-		rrd.name = name;
-		return rrd;
-	}
-
-	/**
-	 * Flush changes from a remote run delegate to the database. Must be called
-	 * within the context of a transaction.
-	 * 
-	 * @param rrd
-	 *            The remote run delegate object that has potential changes.
-	 * @throws IOException
-	 *             If anything goes wrong in serialization.
-	 */
-	public void makeChanges(@Nonnull RemoteRunDelegate rrd) throws IOException {
-		// Properties that are set exactly once
-		if (creationInstant == null) {
-			creationInstant = rrd.getCreationTimestamp();
-			workflow = rrd.getWorkflow();
-			run = new MarshalledObject<>(rrd.run);
-			securityContextFactory = rrd.getSecurityContext().getFactory();
-			owner = rrd.getSecurityContext().getOwner().getName();
-			securityToken = ((org.taverna.server.master.worker.SecurityContextFactory) securityContextFactory)
-					.issueNewPassword();
-		}
-		// Properties that are set multiple times
-		expiry = rrd.getExpiry();
-		readers = rrd.getReaders().toArray(STRING_ARY);
-		writers = rrd.getWriters().toArray(STRING_ARY);
-		destroyers = rrd.getDestroyers().toArray(STRING_ARY);
-		credentials = rrd.getSecurityContext().getCredentials();
-		trust = rrd.getSecurityContext().getTrusted();
-		if (rrd.name.length() > NAME_LENGTH)
-			this.name = rrd.name.substring(0, NAME_LENGTH);
-		else
-			this.name = rrd.name;
-		setFinished(rrd.doneTransitionToFinished);
-		setProvenanceGenerated(rrd.generateProvenance);
-	}
-
-	public String getSecurityToken() {
-		return securityToken;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java
deleted file mode 100644
index 5fa96b8..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.taverna.server.master.notification.NotificationEngine;
-
-/**
- * The interface to the database of runs.
- * 
- * @author Donal Fellows
- */
-public interface RunDBSupport {
-	/**
-	 * Scan each run to see if it has finished yet and issue registered
-	 * notifications if it has.
-	 */
-	void checkForFinishNow();
-
-	/**
-	 * Remove currently-expired runs from this database.
-	 */
-	void cleanNow();
-
-	/**
-	 * How many runs are stored in the database.
-	 * 
-	 * @return The current size of the run table.
-	 */
-	int countRuns();
-
-	/**
-	 * Ensure that a run gets persisted in the database. It is assumed that the
-	 * value is already in there.
-	 * 
-	 * @param run
-	 *            The run to persist.
-	 */
-	void flushToDisk(@Nonnull RemoteRunDelegate run);
-
-	/**
-	 * Select an arbitrary representative run.
-	 * 
-	 * @return The selected run.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	@Nullable
-	RemoteRunDelegate pickArbitraryRun() throws Exception;
-
-	/**
-	 * Get a list of all the run names.
-	 * 
-	 * @return The names (i.e., UUIDs) of all the runs.
-	 */
-	@Nonnull
-	List<String> listRunNames();
-
-	/**
-	 * @param notificationEngine
-	 *            A reference to the notification fabric bean.
-	 */
-	void setNotificationEngine(NotificationEngine notificationEngine);
-
-	/**
-	 * @param notifier
-	 *            A reference to the bean that creates messages about workflow
-	 *            run termination.
-	 */
-	void setNotifier(CompletionNotifier notifier);
-
-	/**
-	 * @return A reference to the actual factory for remote runs.
-	 */
-	FactoryBean getFactory();
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java
deleted file mode 100644
index 65aec70..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static java.lang.Integer.parseInt;
-import static java.util.UUID.randomUUID;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.UUID;
-
-import javax.annotation.Nullable;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.notification.NotificationEngine;
-import org.taverna.server.master.notification.NotificationEngine.Message;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * The main facade bean that interfaces to the database of runs.
- * 
- * @author Donal Fellows
- */
-public class RunDatabase implements RunStore, RunDBSupport {
-	private Log log = LogFactory.getLog("Taverna.Server.Worker.RunDB");
-	RunDatabaseDAO dao;
-	CompletionNotifier backupNotifier;
-	Map<String, CompletionNotifier> typedNotifiers;
-	private NotificationEngine notificationEngine;
-	@Autowired
-	private FactoryBean factory;
-	private Map<String, TavernaRun> cache = new HashMap<>();
-
-	@Override
-	@Required
-	public void setNotifier(CompletionNotifier n) {
-		backupNotifier = n;
-	}
-
-	public void setTypeNotifiers(List<CompletionNotifier> notifiers) {
-		typedNotifiers = new HashMap<>();
-		for (CompletionNotifier n : notifiers)
-			typedNotifiers.put(n.getName(), n);
-	}
-
-	@Required
-	@Override
-	public void setNotificationEngine(NotificationEngine notificationEngine) {
-		this.notificationEngine = notificationEngine;
-	}
-
-	@Required
-	public void setDao(RunDatabaseDAO dao) {
-		this.dao = dao;
-	}
-
-	@Override
-	public void checkForFinishNow() {
-		/*
-		 * Get which runs are actually newly finished; this requires getting the
-		 * candidates from the database and *then* doing the expensive requests
-		 * to the back end to find out the status.
-		 */
-		Map<String, RemoteRunDelegate> notifiable = new HashMap<>();
-		for (RemoteRunDelegate p : dao.getPotentiallyNotifiable())
-			if (p.getStatus() == Status.Finished)
-				notifiable.put(p.getId(), p);
-
-		// Check if there's nothing more to do
-		if (notifiable.isEmpty())
-			return;
-
-		/*
-		 * Tell the database about the ones we've got.
-		 */
-		dao.markFinished(notifiable.keySet());
-
-		/*
-		 * Send out the notifications. The notification addresses are stored in
-		 * the back-end engine, so this is *another* thing that can take time.
-		 */
-		for (RemoteRunDelegate rrd : notifiable.values())
-			for (Listener l : rrd.getListeners())
-				if (l.getName().equals("io")) {
-					try {
-						notifyFinished(rrd.id, l, rrd);
-					} catch (Exception e) {
-						log.warn("failed to do notification of completion", e);
-					}
-					break;
-				}
-	}
-
-	@Override
-	public void cleanNow() {
-		List<String> cleaned;
-		try {
-			cleaned = dao.doClean();
-		} catch (Exception e) {
-			log.warn("failure during deletion of expired runs", e);
-			return;
-		}
-		synchronized (cache) {
-			for (String id : cleaned)
-				cache.remove(id);
-		}
-	}
-
-	@Override
-	public int countRuns() {
-		return dao.countRuns();
-	}
-
-	@Override
-	public void flushToDisk(RemoteRunDelegate run) {
-		try {
-			dao.flushToDisk(run);
-		} catch (IOException e) {
-			throw new RuntimeException(
-					"unexpected problem when persisting run record in database",
-					e);
-		}
-	}
-
-	@Override
-	public RemoteRunDelegate pickArbitraryRun() throws Exception {
-		return dao.pickArbitraryRun();
-	}
-
-	@Override
-	public List<String> listRunNames() {
-		return dao.listRunNames();
-	}
-
-	@Nullable
-	private TavernaRun get(String uuid) {
-		TavernaRun run = null;
-		synchronized (cache) {
-			run = cache.get(uuid);
-		}
-		try {
-			if (run != null)
-				run.ping();
-		} catch (UnknownRunException e) {
-			if (log.isDebugEnabled())
-				log.debug("stale mapping in cache?", e);
-			// Don't need to flush the cache; this happens when cleaning anyway
-			run = null;
-		}
-		if (run == null)
-			run = dao.get(uuid);
-		return run;
-	}
-
-	@Override
-	public TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
-			throws UnknownRunException {
-		// Check first to see if the 'uuid' actually looks like a UUID; if
-		// not, throw it out immediately without logging an exception.
-		try {
-			UUID.fromString(uuid);
-		} catch (IllegalArgumentException e) {
-			if (log.isDebugEnabled())
-				log.debug("run ID does not look like UUID; rejecting...");
-			throw new UnknownRunException();
-		}
-		TavernaRun run = get(uuid);
-		if (run != null && (user == null || p.permitAccess(user, run)))
-			return run;
-		throw new UnknownRunException();
-	}
-
-	@Override
-	public TavernaRun getRun(String uuid) throws UnknownRunException {
-		TavernaRun run = get(uuid);
-		if (run != null)
-			return run;
-		throw new UnknownRunException();
-	}
-
-	@Override
-	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
-		synchronized (cache) {
-			Map<String, TavernaRun> cached = new HashMap<>();
-			for (Entry<String, TavernaRun> e : cache.entrySet()) {
-				TavernaRun r = e.getValue();
-				if (p.permitAccess(user, r))
-					cached.put(e.getKey(), r);
-			}
-			if (!cached.isEmpty())
-				return cached;
-		}
-		return dao.listRuns(user, p);
-	}
-
-	private void logLength(String message, Object obj) {
-		if (!log.isDebugEnabled())
-			return;
-		try {
-			ByteArrayOutputStream baos = new ByteArrayOutputStream();
-			try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
-				oos.writeObject(obj);
-			}
-			log.debug(message + ": " + baos.size());
-		} catch (Exception e) {
-			log.warn("oops", e);
-		}
-	}
-
-	@Override
-	public String registerRun(TavernaRun run) {
-		if (!(run instanceof RemoteRunDelegate))
-			throw new IllegalArgumentException(
-					"run must be created by localworker package");
-		RemoteRunDelegate rrd = (RemoteRunDelegate) run;
-		if (rrd.id == null)
-			rrd.id = randomUUID().toString();
-		logLength("RemoteRunDelegate serialized length", rrd);
-		try {
-			dao.persistRun(rrd);
-		} catch (IOException e) {
-			throw new RuntimeException(
-					"unexpected problem when persisting run record in database",
-					e);
-		}
-		synchronized (cache) {
-			cache.put(rrd.getId(), run);
-		}
-		return rrd.getId();
-	}
-
-	@Override
-	public void unregisterRun(String uuid) {
-		try {
-			if (dao.unpersistRun(uuid))
-				synchronized (cache) {
-					cache.remove(uuid);
-				}
-		} catch (RuntimeException e) {
-			if (log.isDebugEnabled())
-				log.debug("problem persisting the deletion of the run " + uuid,
-						e);
-		}
-	}
-
-	/**
-	 * Process the event that a run has finished.
-	 * 
-	 * @param name
-	 *            The name of the run.
-	 * @param io
-	 *            The io listener of the run (used to get information about the
-	 *            run).
-	 * @param run
-	 *            The handle to the run.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	private void notifyFinished(final String name, Listener io,
-			final RemoteRunDelegate run) throws Exception {
-		String to = io.getProperty("notificationAddress");
-		final int code;
-		try {
-			code = parseInt(io.getProperty("exitcode"));
-		} catch (NumberFormatException nfe) {
-			// Ignore; not much we can do here...
-			return;
-		}
-
-		notificationEngine.dispatchMessage(run, to, new Message() {
-			private CompletionNotifier getNotifier(String type) {
-				CompletionNotifier n = typedNotifiers.get(type);
-				if (n == null)
-					n = backupNotifier;
-				return n;
-			}
-
-			@Override
-			public String getContent(String type) {
-				return getNotifier(type).makeCompletionMessage(name, run, code);
-			}
-
-			@Override
-			public String getTitle(String type) {
-				return getNotifier(type).makeMessageSubject(name, run, code);
-			}
-		});
-	}
-
-	@Override
-	public FactoryBean getFactory() {
-		return factory;
-	}
-}


[30/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Workflow.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Workflow.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Workflow.java
new file mode 100644
index 0000000..3a7d5f7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Workflow.java
@@ -0,0 +1,380 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import static javax.xml.bind.Marshaller.JAXB_ENCODING;
+import static javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT;
+import static javax.xml.bind.annotation.XmlAccessType.NONE;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.net.URL;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.taverna.server.master.rest.handler.Scufl2DocumentHandler;
+import org.taverna.server.master.rest.handler.T2FlowDocumentHandler;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import org.apache.taverna.scufl2.api.common.NamedSet;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.io.ReaderException;
+import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
+import org.apache.taverna.scufl2.api.io.WriterException;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Encapsulation of a T2flow or Scufl2 document.
+ * 
+ * @author Donal K. Fellows
+ */
+@XmlRootElement(name = "workflow")
+@XmlType(name = "Workflow")
+@XmlAccessorType(NONE)
+public class Workflow implements Serializable, Externalizable {
+	/** Literal document, if present. */
+	@XmlAnyElement(lax = true)
+	private Element content;
+	/** SCUFL2 bundle, if present. */
+	@XmlTransient
+	private WorkflowBundle bundle;
+	/** Which came first, the bundle or the t2flow document. */
+	@XmlTransient
+	private boolean isBundleFirst;
+
+	private static Marshaller marshaller;
+	private static Unmarshaller unmarshaller;
+	private final static String ENCODING = "UTF-8";
+	private final static WorkflowBundleIO io;
+	static {
+		try {
+			JAXBContext context = JAXBContext.newInstance(Workflow.class);
+			marshaller = context.createMarshaller();
+			unmarshaller = context.createUnmarshaller();
+			marshaller.setProperty(JAXB_ENCODING, ENCODING);
+			marshaller.setProperty(JAXB_FORMATTED_OUTPUT, false);
+		} catch (JAXBException e) {
+			getLog("Taverna.Server.Webapp").fatal(
+					"failed to build JAXB context for working with "
+							+ Workflow.class, e);
+		}
+		io = new WorkflowBundleIO();
+	}
+
+	public enum ContentType {
+		T2FLOW(T2FlowDocumentHandler.T2FLOW), SCUFL2(
+				Scufl2DocumentHandler.SCUFL2);
+		private String type;
+
+		ContentType(String type) {
+			this.type = type;
+		}
+
+		public String getContentType() {
+			return type;
+		}
+	}
+
+	public Workflow() {
+	}
+
+	public Workflow(Element element) {
+		this.content = element;
+		this.isBundleFirst = false;
+	}
+
+	public Workflow(WorkflowBundle bundle) {
+		this.bundle = bundle;
+		this.isBundleFirst = true;
+	}
+
+	public Workflow(URL url) throws ReaderException, IOException {
+		this(io.readBundle(url, null));
+	}
+
+	/**
+	 * What content type would this workflow "prefer" to be?
+	 */
+	public ContentType getPreferredContentType() {
+		if (isBundleFirst)
+			return ContentType.SCUFL2;
+		else
+			return ContentType.T2FLOW;
+	}
+
+	/**
+	 * Retrieves the workflow as a SCUFL2 document, converting it if necessary.
+	 * 
+	 * @return The SCUFL2 document.
+	 * @throws IOException
+	 *             If anything goes wrong.
+	 */
+	public WorkflowBundle getScufl2Workflow() throws IOException {
+		try {
+			if (bundle == null)
+				bundle = io.readBundle(new ByteArrayInputStream(getAsT2Flow()),
+						T2FLOW);
+			return bundle;
+		} catch (IOException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new IOException("problem when converting to SCUFL2", e);
+		}
+	}
+
+	/**
+	 * Get the bytes of the serialized SCUFL2 workflow.
+	 * 
+	 * @return Array of bytes.
+	 * @throws IOException
+	 *             If serialization fails.
+	 * @throws WriterException
+	 *             If conversion fails.
+	 */
+	public byte[] getScufl2Bytes() throws IOException, WriterException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		io.writeBundle(getScufl2Workflow(), baos, SCUFL2);
+		return baos.toByteArray();
+	}
+
+	/**
+	 * Retrieves the workflow as a T2Flow document, converting it if necessary.
+	 * 
+	 * @return The T2Flow document.
+	 * @throws IOException
+	 *             If anything goes wrong.
+	 */
+	public Element getT2flowWorkflow() throws IOException {
+		try {
+			if (content != null)
+				return content;
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			io.writeBundle(bundle, baos, T2FLOW);
+			Document doc;
+			try {
+				DocumentBuilderFactory dbf = DocumentBuilderFactory
+						.newInstance();
+				dbf.setNamespaceAware(true);
+				doc = dbf.newDocumentBuilder().parse(
+						new ByteArrayInputStream(baos.toByteArray()));
+			} catch (SAXException e) {
+				throw new IOException("failed to convert to DOM tree", e);
+			}
+			Element e = doc.getDocumentElement();
+			if (e.getNamespaceURI().equals(T2FLOW_NS)
+					&& e.getNodeName().equals(T2FLOW_ROOTNAME))
+				return content = e;
+			throw new IOException(
+					"unexpected element when converting to T2Flow: {"
+							+ e.getNamespaceURI() + "}" + e.getNodeName());
+		} catch (IOException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new IOException("problem when converting to SCUFL2", e);
+		}
+	}
+
+	/**
+	 * @return The name of the main workflow profile, or <tt>null</tt> if there
+	 *         is none.
+	 */
+	public String getMainProfileName() {
+		try {
+			return getScufl2Workflow().getMainProfile().getName();
+		} catch (IOException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * @return The set of profiles supported over this workflow.
+	 */
+	public NamedSet<Profile> getProfiles() {
+		try {
+			return getScufl2Workflow().getProfiles();
+		} catch (IOException e) {
+			return new NamedSet<Profile>();
+		}
+	}
+
+	/**
+	 * Convert from marshalled form.
+	 * 
+	 * @throws JAXBException
+	 *             If the conversion fails.
+	 */
+	public static Workflow unmarshal(String representation)
+			throws JAXBException {
+		StringReader sr = new StringReader(representation);
+		return (Workflow) unmarshaller.unmarshal(sr);
+	}
+
+	/**
+	 * Convert to marshalled form.
+	 */
+	public String marshal() throws JAXBException {
+		StringWriter sw = new StringWriter();
+		marshaller.marshal(this, sw);
+		return sw.toString();
+	}
+
+	@Override
+	public void readExternal(ObjectInput in) throws IOException,
+			ClassNotFoundException {
+		try {
+			ByteArrayInputStream bytes = readbytes(in);
+			if (bytes != null)
+				try (Reader r = new InputStreamReader(bytes, ENCODING)) {
+					content = ((Workflow) unmarshaller.unmarshal(r)).content;
+				}
+			bytes = readbytes(in);
+			if (bytes != null)
+				bundle = io.readBundle(bytes, SCUFL2);
+			isBundleFirst = in.readBoolean();
+			return;
+		} catch (JAXBException e) {
+			throw new IOException("failed to unmarshal", e);
+		} catch (ClassCastException e) {
+			throw new IOException("bizarre result of unmarshalling", e);
+		} catch (ReaderException e) {
+			throw new IOException("failed to unmarshal", e);
+		}
+	}
+
+	private byte[] getAsT2Flow() throws IOException, JAXBException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		OutputStreamWriter w = new OutputStreamWriter(baos, ENCODING);
+		marshaller.marshal(this, w);
+		w.close();
+		return baos.toByteArray();
+	}
+
+	private byte[] getAsScufl2() throws IOException, WriterException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		io.writeBundle(bundle, baos, SCUFL2);
+		baos.close();
+		return baos.toByteArray();
+	}
+
+	@Override
+	public void writeExternal(ObjectOutput out) throws IOException {
+		try {
+			writebytes(out, (content != null) ? getAsT2Flow() : null);
+		} catch (JAXBException e) {
+			throw new IOException("failed to marshal t2flow", e);
+		}
+		try {
+			writebytes(out, (bundle != null) ? getAsScufl2() : null);
+		} catch (WriterException e) {
+			throw new IOException("failed to marshal scufl2", e);
+		}
+		out.writeBoolean(isBundleFirst);
+	}
+
+	private ByteArrayInputStream readbytes(ObjectInput in) throws IOException {
+		int len = in.readInt();
+		if (len > 0) {
+			byte[] bytes = new byte[len];
+			in.readFully(bytes);
+			return new ByteArrayInputStream(bytes);
+		}
+		return null;
+	}
+
+	private void writebytes(ObjectOutput out, byte[] data) throws IOException {
+		out.writeInt(data == null ? 0 : data.length);
+		if (data != null && data.length > 0)
+			out.write(data);
+	}
+
+	/**
+	 * Make up for the lack of an integrated XPath engine.
+	 * 
+	 * @param name
+	 *            The element names to look up from the root of the contained
+	 *            document.
+	 * @return The looked up element, or <tt>null</tt> if it doesn't exist.
+	 */
+	private Element getEl(String... name) {
+		Element el = content;
+		boolean skip = true;
+		for (String n : name) {
+			if (skip) {
+				skip = false;
+				continue;
+			}
+			if (el == null)
+				return null;
+			NodeList nl = el.getElementsByTagNameNS(T2FLOW_NS, n);
+			if (nl.getLength() == 0)
+				return null;
+			Node node = nl.item(0);
+			if (node instanceof Element)
+				el = (Element) node;
+			else
+				return null;
+		}
+		return el;
+	}
+
+	/**
+	 * @return The content of the embedded
+	 *         <tt>&lt;workflow&gt;&lt;dataflow&gt;&lt;name&gt;</tt> element.
+	 */
+	@XmlTransient
+	public String getName() {
+		return getEl("workflow", "dataflow", "name").getTextContent();
+	}
+
+	/**
+	 * @return The embedded <tt>&lt;workflow&gt;</tt> element.
+	 */
+	@XmlTransient
+	public Element getWorkflowRoot() {
+		return getEl("workflow");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/package-info.java
new file mode 100644
index 0000000..e000cef
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/package-info.java
@@ -0,0 +1,42 @@
+/*
+ */
+/**
+ * This package contains the common XML elements used throughout Taverna Server's various interfaces.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.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/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/version/Version.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/version/Version.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/version/Version.java
new file mode 100644
index 0000000..bd50db2
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/version/Version.java
@@ -0,0 +1,56 @@
+/*
+ */
+package org.taverna.server.master.common.version;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static org.taverna.server.master.common.version.Constants.PATCH;
+import static org.taverna.server.master.common.version.Constants.VERSION;
+
+/**
+ * Common location for describing the version of the server.
+ * 
+ * @author Donal Fellows
+ */
+public interface Version {
+	public static final String JAVA = VERSION + Constants.releaseChar + PATCH;
+	public static final String HTML = VERSION + Constants.releaseHEnt + PATCH;
+	public static final String XML = VERSION + Constants.releaseXEnt + PATCH;
+}
+
+/**
+ * The pieces of a version string.
+ * 
+ * @author Donal Fellows
+ */
+interface Constants {
+	static final String MAJOR = "3";
+	static final String MINOR = "1";
+	static final String PATCH = "0";
+
+	static final char alphaChar = '\u03b1';
+	static final char betaChar = '\u03b2';
+	static final char releaseChar = '.';
+	static final String alphaHEnt = "&alpha;";
+	static final String betaHEnt = "&beta;";
+	static final String releaseHEnt = ".";
+	static final String alphaXEnt = "&#x03b1;";
+	static final String betaXEnt = "&#x03b2;";
+	static final String releaseXEnt = ".";
+
+	static final String VERSION = MAJOR + "." + MINOR;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/Default.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/Default.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/Default.java
new file mode 100644
index 0000000..679a5f4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/Default.java
@@ -0,0 +1,112 @@
+/*
+ */
+package org.taverna.server.master.defaults;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.localworker.LocalWorkerState;
+
+/**
+ * This defines a collection of default values, collecting them from various
+ * parts of the server.
+ * 
+ * @author Donal Fellows
+ */
+public interface Default {
+	/** The default value of the <tt>prefix</tt> property. */
+	static final String AUTHORITY_PREFIX = "LOCALUSER_";
+
+	/**
+	 * The name of the resource that is the implementation of the subprocess
+	 * that this class will fork off.
+	 */
+	static final String SERVER_WORKER_IMPLEMENTATION_JAR = "util/server.worker.jar";
+
+	/**
+	 * The name of the resource that is the implementation of the subprocess
+	 * that manages secure forking.
+	 */
+	static final String SECURE_FORK_IMPLEMENTATION_JAR = "util/secure.fork.jar";
+
+	/**
+	 * The name of the resource that is the implementation of the subprocess
+	 * that acts as the RMI registry.
+	 */
+	static final String REGISTRY_JAR = "util/rmi.daemon.jar";
+
+	/** Initial lifetime of runs, in minutes. */
+	static final int RUN_LIFE_MINUTES = 20;
+
+	/**
+	 * Maximum number of runs to exist at once. Note that this includes when
+	 * they are just existing for the purposes of file transfer (
+	 * {@link Status#Initialized}/{@link Status#Finished} states).
+	 */
+	static final int RUN_COUNT_MAX = 5;
+
+	/**
+	 * Prefix to use for RMI names.
+	 */
+	static final String RMI_PREFIX = "ForkRunFactory.";
+
+	/** Default value for {@link LocalWorkerState#passwordFile}. */
+	static final String PASSWORD_FILE = null;
+
+	/**
+	 * The extra arguments to pass to the subprocess.
+	 */
+	static final String[] EXTRA_ARGUMENTS = new String[0];
+
+	/**
+	 * How long to wait for subprocess startup, in seconds.
+	 */
+	static final int SUBPROCESS_START_WAIT = 40;
+
+	/**
+	 * Polling interval to use during startup, in milliseconds.
+	 */
+	static final int SUBPROCESS_START_POLL_SLEEP = 1000;
+
+	/**
+	 * Maximum number of {@link Status#Operating} runs at any time.
+	 */
+	static final int RUN_OPERATING_LIMIT = 10;
+
+	/**
+	 * What fields of a certificate we look at when understanding who it is
+	 * talking about, in the order that we look.
+	 */
+	static final String[] CERTIFICATE_FIELD_NAMES = { "CN", "COMMONNAME",
+			"COMMON NAME", "COMMON_NAME", "OU", "ORGANIZATIONALUNITNAME",
+			"ORGANIZATIONAL UNIT NAME", "O", "ORGANIZATIONNAME",
+			"ORGANIZATION NAME" };
+
+	/** The type of certificates that are processed if we don't say otherwise. */
+	static final String CERTIFICATE_TYPE = "X.509";
+
+	/** Max size of credential file, in kiB. */
+	static final int CREDENTIAL_FILE_SIZE_LIMIT = 20;
+
+	/**
+	 * The notification message format to use if none is configured.
+	 */
+	public static final String NOTIFY_MESSAGE_FORMAT = "Your job with ID={0} has finished with exit code {1,number,integer}.";
+
+	/** The address of the SMS gateway service used. */
+	public static final String SMS_GATEWAY_URL = "https://www.intellisoftware.co.uk/smsgateway/sendmsg.aspx";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/package-info.java
new file mode 100644
index 0000000..5585c77
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/package-info.java
@@ -0,0 +1,21 @@
+/**
+ * This package contains information about the various default values supported by the server.
+ * @author Donal Fellows
+ */
+package org.taverna.server.master.defaults;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadInputPortNameException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadInputPortNameException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadInputPortNameException.java
new file mode 100644
index 0000000..64d07f0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadInputPortNameException.java
@@ -0,0 +1,34 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Indicates that the port name was not recognized.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "BadInputPortNameFault")
+@SuppressWarnings("serial")
+public class BadInputPortNameException extends Exception {
+	public BadInputPortNameException(String msg) {
+		super(msg);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadPropertyValueException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadPropertyValueException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadPropertyValueException.java
new file mode 100644
index 0000000..61bf740
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadPropertyValueException.java
@@ -0,0 +1,39 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Indicates a bad property value.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "BadPropertyValueFault")
+public class BadPropertyValueException extends NoListenerException {
+	private static final long serialVersionUID = -8459491388504556875L;
+
+	public BadPropertyValueException(String msg) {
+		super(msg);
+	}
+
+	public BadPropertyValueException(String msg, Throwable e) {
+		super(msg, e);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadStateChangeException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadStateChangeException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadStateChangeException.java
new file mode 100644
index 0000000..152410f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadStateChangeException.java
@@ -0,0 +1,48 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that is thrown to indicate that the state change requested for a
+ * run is impossible.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoUpdateFault")
+public class BadStateChangeException extends NoUpdateException {
+	private static final long serialVersionUID = -4490826388447601775L;
+
+	public BadStateChangeException() {
+		super("cannot do that state change");
+	}
+
+	public BadStateChangeException(Throwable t) {
+		super("cannot do that state change", t);
+	}
+
+	public BadStateChangeException(String msg, Throwable t) {
+		super(msg, t);
+	}
+
+	public BadStateChangeException(String message) {
+		super(message);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/FilesystemAccessException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/FilesystemAccessException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/FilesystemAccessException.java
new file mode 100644
index 0000000..e0894e4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/FilesystemAccessException.java
@@ -0,0 +1,51 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import java.rmi.RemoteException;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * An exception that happened when the underlying filesystem was accessed.
+ * @author Donal Fellows
+ */
+@WebFault(name = "FilesystemAccessFault")
+public class FilesystemAccessException extends Exception {
+	private static final long serialVersionUID = 8715937300989820318L;
+
+	public FilesystemAccessException(String msg) {
+		super(msg);
+	}
+
+	public FilesystemAccessException(String string, Throwable cause) {
+		super(string, getRealCause(cause));
+	}
+
+	private static Throwable getRealCause(Throwable t) {
+		if (t instanceof RemoteException) {
+			RemoteException remote = (RemoteException) t;
+			if (remote.detail != null)
+				return remote.detail;
+		}
+		if (t.getCause() != null)
+			return t.getCause();
+		return t;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/GeneralFailureException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/GeneralFailureException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/GeneralFailureException.java
new file mode 100644
index 0000000..de3fab5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/GeneralFailureException.java
@@ -0,0 +1,41 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Some sort of exception that occurred which we can't map any other way. This
+ * is generally indicative of a problem server-side.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "GeneralFailureFault", targetNamespace = SERVER_SOAP)
+@SuppressWarnings("serial")
+public class GeneralFailureException extends RuntimeException {
+	public GeneralFailureException(Throwable cause) {
+		super(cause.getMessage(), cause);
+	}
+
+	public GeneralFailureException(String message, Throwable cause) {
+		super(message, cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/InvalidCredentialException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/InvalidCredentialException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/InvalidCredentialException.java
new file mode 100644
index 0000000..7e00093
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/InvalidCredentialException.java
@@ -0,0 +1,49 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+/**
+ * An exception that is thrown to indicate that a credential-descriptor or
+ * trust-descriptor supplied as part of a credential or trust management
+ * operation is invalid.
+ * 
+ * @author Donal Fellows
+ * 
+ */
+@SuppressWarnings("serial")
+public class InvalidCredentialException extends Exception {
+	private static final String MSG = "that credential is invalid";
+
+	public InvalidCredentialException() {
+		super(MSG);
+	}
+
+	public InvalidCredentialException(String reason) {
+		super(MSG + ": " + reason);
+	}
+
+	public InvalidCredentialException(String reason, Throwable cause) {
+		this(reason);
+		initCause(cause);
+	}
+
+	public InvalidCredentialException(Throwable cause) {
+		this(cause.getMessage(), cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCreateException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCreateException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCreateException.java
new file mode 100644
index 0000000..d665adb
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCreateException.java
@@ -0,0 +1,45 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.ws.WebFault;
+
+
+/**
+ * Exception that is thrown to indicate that the user is not permitted to
+ * create something.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoCreateFault")
+public class NoCreateException extends NoUpdateException {
+	private static final long serialVersionUID = 270413810410167235L;
+
+	public NoCreateException() {
+		super("not permitted to create");
+	}
+
+	public NoCreateException(String string) {
+		super(string);
+	}
+
+	public NoCreateException(String string, Throwable e) {
+		super(string, e);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCredentialException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCredentialException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCredentialException.java
new file mode 100644
index 0000000..b351c1c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCredentialException.java
@@ -0,0 +1,31 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+/**
+ * Exception that indicates the absence of an expected credential.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+public class NoCredentialException extends Exception {
+	public NoCredentialException() {
+		super("no such credential");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDestroyException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDestroyException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDestroyException.java
new file mode 100644
index 0000000..42de7d1
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDestroyException.java
@@ -0,0 +1,37 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.ws.WebFault;
+
+
+/**
+ * Exception that is thrown to indicate that the user is not permitted to
+ * destroy something.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoDestroyFault")
+public class NoDestroyException extends NoUpdateException {
+	private static final long serialVersionUID = 6207448533265237933L;
+
+	public NoDestroyException() {
+		super("not permitted to destroy");
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDirectoryEntryException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDirectoryEntryException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDirectoryEntryException.java
new file mode 100644
index 0000000..32300d1
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoDirectoryEntryException.java
@@ -0,0 +1,37 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Indicates that the file or directory name was not recognized.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoDirectoryEntryFault")
+@SuppressWarnings("serial")
+public class NoDirectoryEntryException extends Exception {
+	public NoDirectoryEntryException(String msg) {
+		super(msg);
+	}
+	public NoDirectoryEntryException(String msg,Exception cause) {
+		super(msg, cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoListenerException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoListenerException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoListenerException.java
new file mode 100644
index 0000000..ef84e9e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoListenerException.java
@@ -0,0 +1,46 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception thrown to indicate that no listener by that name exists, or that
+ * some other problem with listeners has occurred.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoListenerFault")
+@XmlSeeAlso(BadPropertyValueException.class)
+public class NoListenerException extends Exception {
+	private static final long serialVersionUID = -2550897312787546547L;
+
+	public NoListenerException() {
+		super("no such listener");
+	}
+
+	public NoListenerException(String msg) {
+		super(msg);
+	}
+
+	public NoListenerException(String msg, Throwable t) {
+		super(msg, t);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoUpdateException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoUpdateException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoUpdateException.java
new file mode 100644
index 0000000..5e972dd
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoUpdateException.java
@@ -0,0 +1,46 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that is thrown to indicate that the user is not permitted to update
+ * something.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoUpdateFault")
+@XmlSeeAlso( { NoCreateException.class, NoDestroyException.class, BadStateChangeException.class })
+public class NoUpdateException extends Exception {
+	private static final long serialVersionUID = 4230987102653846379L;
+
+	public NoUpdateException() {
+		super("not permitted to update");
+	}
+
+	public NoUpdateException(String msg) {
+		super(msg);
+	}
+
+	public NoUpdateException(String string, Throwable e) {
+		super(string, e);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NotOwnerException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NotOwnerException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NotOwnerException.java
new file mode 100644
index 0000000..29e00b7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NotOwnerException.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.ws.WebFault;
+
+/**
+ * An exception thrown when an operation is attempted which only the owner is
+ * permitted to do. Notably, permissions may <i>only</i> be manipulated by the
+ * owner.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NotOwnerFault")
+@SuppressWarnings("serial")
+public class NotOwnerException extends Exception {
+	public NotOwnerException() {
+		super("not permitted; not the owner");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/OverloadedException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/OverloadedException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/OverloadedException.java
new file mode 100644
index 0000000..bd34659
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/OverloadedException.java
@@ -0,0 +1,48 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that is thrown to indicate that the state change requested for a
+ * run is currently impossible due to excessive server load.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "OverloadedFault")
+public class OverloadedException extends BadStateChangeException {
+	private static final long serialVersionUID = 490826388447601776L;
+
+	public OverloadedException() {
+		super("server too busy; try later please");
+	}
+
+	public OverloadedException(Throwable t) {
+		super("server too busy; try later please", t);
+	}
+
+	public OverloadedException(String msg, Throwable t) {
+		super(msg, t);
+	}
+
+	public OverloadedException(String message) {
+		super(message);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/UnknownRunException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/UnknownRunException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/UnknownRunException.java
new file mode 100644
index 0000000..af717ab
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/UnknownRunException.java
@@ -0,0 +1,40 @@
+/*
+ */
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception thrown to indicate that the handle of the run is unknown (or
+ * unacceptable to the current user).
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "UnknownRunFault")
+public class UnknownRunException extends Exception {
+	private static final long serialVersionUID = -3028749401786242841L;
+
+	public UnknownRunException() {
+		super("unknown run UUID");
+	}
+
+	public UnknownRunException(Throwable t) {
+		super("implementation problems", t);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/package-info.java
new file mode 100644
index 0000000..b2284ee
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/package-info.java
@@ -0,0 +1,42 @@
+/*
+ */
+/**
+ * This package contains the exceptions/faults thrown by Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.exceptions;
+/*
+ * 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.
+ */
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.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/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/Facade.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/Facade.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/Facade.java
new file mode 100644
index 0000000..3031520
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/Facade.java
@@ -0,0 +1,86 @@
+/*
+ */
+package org.taverna.server.master.facade;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.MediaType.TEXT_HTML_TYPE;
+import static javax.ws.rs.core.Response.ok;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.utils.Contextualizer;
+
+/**
+ * This is a simple class that is used to serve up a file (with a simple
+ * substitution applied) as the root of the T2Server webapp.
+ * 
+ * @author Donal Fellows
+ */
+@Path("/")
+public class Facade {
+	private Log log = LogFactory.getLog("Taverna.Server.Utils");
+	private String welcome;
+	private Contextualizer contextualizer;
+
+	/**
+	 * Set what resource file to use as the template for the response.
+	 * 
+	 * @param file
+	 *            The file from which to load the data (presumed HTML) to serve
+	 *            up as the root content.
+	 * @throws IOException
+	 *             If the file doesn't exist.
+	 */
+	public void setFile(String file) throws IOException {
+		URL full = Facade.class.getResource(file);
+		log.info("setting " + full + " as source of root page");
+		this.welcome = IOUtils.toString(full);
+	}
+
+	@Required
+	public void setContextualizer(Contextualizer contextualizer) {
+		this.contextualizer = contextualizer;
+	}
+
+	/**
+	 * Serve up some HTML as the root of the service.
+	 * 
+	 * @param ui
+	 *            A reference to how we were accessed by the service.
+	 * @return The response, containing the HTML.
+	 */
+	@GET
+	@Path("{dummy:.*}")
+	@Produces("text/html")
+	public Response get(@Context UriInfo ui) {
+		return ok(contextualizer.contextualize(ui, welcome), TEXT_HTML_TYPE)
+				.build();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/package-info.java
new file mode 100644
index 0000000..2d8f4ef
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/facade/package-info.java
@@ -0,0 +1,23 @@
+/*
+ */
+/**
+ * Simple facade used at the top level of the Taverna Server in order to
+ * provide an entry splash page.
+ */
+package org.taverna.server.master.facade;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ConfigurableRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ConfigurableRunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ConfigurableRunFactory.java
new file mode 100644
index 0000000..7a4124d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ConfigurableRunFactory.java
@@ -0,0 +1,146 @@
+/*
+ */
+package org.taverna.server.master.factories;
+/*
+ * 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.
+ */
+
+/**
+ * Interface to run factories for the purpose of configuration.
+ * 
+ * @author Donal Fellows
+ */
+public interface ConfigurableRunFactory extends RunFactory {
+	/** Where is the registry? Getter */
+	String getRegistryHost();
+
+	/** Where is the registry? Setter */
+	void setRegistryHost(String host);
+
+	/** Where is the registry? Getter */
+	int getRegistryPort();
+
+	/** Where is the registry? Setter */
+	void setRegistryPort(int port);
+
+	/** How much can be done at once? Getter */
+	int getMaxRuns();
+
+	/** How much can be done at once? Setter */
+	void setMaxRuns(int maxRuns);
+
+	/** How long will things live? Getter */
+	int getDefaultLifetime();
+
+	/** How long will things live? Setter */
+	void setDefaultLifetime(int defaultLifetime);
+
+	/** How often do we probe for info? Getter */
+	int getSleepTime();
+
+	/** How often do we probe for info? Setter */
+	void setSleepTime(int sleepTime);
+
+	/** How long do we allow for actions? Getter */
+	int getWaitSeconds();
+
+	/** How long do we allow for actions? Setter */
+	void setWaitSeconds(int seconds);
+
+	/** How do we start the workflow engine? Getter */
+	String getExecuteWorkflowScript();
+
+	/** How do we start the workflow engine? Setter */
+	void setExecuteWorkflowScript(String executeWorkflowScript);
+
+	/** How do we start the file system access process? Getter */
+	String getServerWorkerJar();
+
+	/** How do we start the file system access process? Setter */
+	void setServerWorkerJar(String serverWorkerJar);
+
+	/**
+	 * How do we start the file system access process? Extra arguments to pass.
+	 * Getter
+	 */
+	String[] getExtraArguments();
+
+	/**
+	 * How do we start the file system access process? Extra arguments to pass.
+	 * Setter
+	 */
+	void setExtraArguments(String[] firstArguments);
+
+	/** Where is Java? Getter */
+	String getJavaBinary();
+
+	/** Where is Java? Setter */
+	void setJavaBinary(String javaBinary);
+
+	/** Where do we get passwords from? Getter */
+	String getPasswordFile();
+
+	/** Where do we get passwords from? Setter */
+	void setPasswordFile(String newValue);
+
+	/** How do we switch users? Getter */
+	String getServerForkerJar();
+
+	/** How do we switch users? Setter */
+	void setServerForkerJar(String newValue);
+
+	/** How many runs have there been? */
+	int getTotalRuns();
+
+	/** How long did the last subprocess startup take? */
+	int getLastStartupCheckCount();
+
+	/** What are the current runs? */
+	String[] getCurrentRunNames();
+
+	/** What is the RMI ID of the factory process? */
+	String getFactoryProcessName();
+
+	/** What was the last observed exit code? */
+	Integer getLastExitCode();
+
+	/** What factory process to use for a particular user? */
+	String[] getFactoryProcessMapping();
+
+	/** How many runs can be operating at once? Setter */
+	void setOperatingLimit(int operatingLimit);
+
+	/** How many runs can be operating at once? Getter */
+	int getOperatingLimit();
+
+	/**
+	 * How many runs are actually operating?
+	 * 
+	 * @throws Exception
+	 *             if anything goes wrong
+	 */
+	int getOperatingCount() throws Exception;
+
+	/** How do we start the RMI registry process? Getter */
+	String getRmiRegistryJar();
+
+	/** How do we start the RMI registry process? Setter */
+	void setRmiRegistryJar(String rmiRegistryJar);
+
+	boolean getGenerateProvenance();
+
+	void setGenerateProvenance(boolean generateProvenance);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ListenerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ListenerFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ListenerFactory.java
new file mode 100644
index 0000000..bb83401
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/ListenerFactory.java
@@ -0,0 +1,59 @@
+/*
+ */
+package org.taverna.server.master.factories;
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * How to make event listeners of various types that are attached to a workflow
+ * instance.
+ * 
+ * @author Donal Fellows
+ */
+public interface ListenerFactory {
+	/**
+	 * Make an event listener.
+	 * 
+	 * @param run
+	 *            The workflow instance to attach the event listener to.
+	 * @param listenerType
+	 *            The type of event listener to create. Must be one of the
+	 *            strings returned by {@link #getSupportedListenerTypes()}.
+	 * @param configuration
+	 *            A configuration document to pass to the listener.
+	 * @return The event listener that was created.
+	 * @throws NoListenerException
+	 *             If the <b>listenerType</b> is unrecognized or the
+	 *             <b>configuration</b> is bad in some way.
+	 */
+	public Listener makeListener(TavernaRun run, String listenerType,
+			String configuration) throws NoListenerException;
+
+	/**
+	 * What types of listener are supported? Note that we assume that the list
+	 * of types is the same for all users and all workflow instances.
+	 * 
+	 * @return A list of supported listener types.
+	 */
+	public List<String> getSupportedListenerTypes();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/RunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/RunFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/RunFactory.java
new file mode 100644
index 0000000..d048f70
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/RunFactory.java
@@ -0,0 +1,53 @@
+/*
+ */
+package org.taverna.server.master.factories;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * How to construct a Taverna Server Workflow Run.
+ * 
+ * @author Donal Fellows
+ */
+public interface RunFactory {
+	/**
+	 * Make a Taverna Server workflow run that is bound to a particular user
+	 * (the "creator") and able to run a particular workflow.
+	 * 
+	 * @param creator
+	 *            The user creating the workflow instance.
+	 * @param workflow
+	 *            The workflow to instantiate
+	 * @return An object representing the run.
+	 * @throws NoCreateException
+	 *             On failure.
+	 */
+	TavernaRun create(UsernamePrincipal creator, Workflow workflow)
+			throws NoCreateException;
+
+	/**
+	 * Check whether the factory is permitting runs to actually start operating.
+	 * 
+	 * @return Whether a run should start.
+	 */
+	boolean isAllowingRunsToStart();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/package-info.java
new file mode 100644
index 0000000..56ba1e2
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/factories/package-info.java
@@ -0,0 +1,23 @@
+/*
+ */
+/**
+ * These interfaces define the principal way for the <i>factories</i> of
+ * worker classes to be invoked.
+ */
+package org.taverna.server.master.factories;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/AuthorityDerivedIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/AuthorityDerivedIDMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/AuthorityDerivedIDMapper.java
new file mode 100644
index 0000000..4fd5312
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/AuthorityDerivedIDMapper.java
@@ -0,0 +1,63 @@
+/*
+ */
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Extracts the local user id from the set of Spring Security authorities
+ * granted to the current user. This is done by scanning the set of authorities
+ * to see if any of them start with the substring listed in the <tt>prefix</tt>
+ * property; the username is the rest of the authority string in that case.
+ * 
+ * @author Donal Fellows
+ */
+public class AuthorityDerivedIDMapper implements LocalIdentityMapper {
+	private String prefix = AUTHORITY_PREFIX;
+
+	public String getPrefix() {
+		return prefix;
+	}
+
+	public void setPrefix(String prefix) {
+		this.prefix = prefix;
+	}
+
+	@Override
+	public String getUsernameForPrincipal(UsernamePrincipal user) {
+		Authentication auth = SecurityContextHolder.getContext()
+				.getAuthentication();
+		if (auth == null || !auth.isAuthenticated())
+			return null;
+		for (GrantedAuthority authority : auth.getAuthorities()) {
+			String token = authority.getAuthority();
+			if (token == null)
+				continue;
+			if (token.startsWith(prefix))
+				return token.substring(prefix.length());
+		}
+		return null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/CompositeIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/CompositeIDMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/CompositeIDMapper.java
new file mode 100644
index 0000000..f0a6f4c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/CompositeIDMapper.java
@@ -0,0 +1,78 @@
+/*
+ */
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */
+
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * An identity mapper that composes the results from other mappers, using the
+ * identity mappers in order until one can provide a non-<tt>null</tt> answer.
+ * 
+ * @author Donal Fellows.
+ */
+public class CompositeIDMapper implements LocalIdentityMapper,
+		ApplicationContextAware {
+	private Log log = getLog("Taverna.Server.IdentityMapper");
+	private List<LocalIdentityMapper> mappers;
+	private ApplicationContext context;
+
+	/**
+	 * @param mappers
+	 *            The list of mappers to delegate to. Order is significant.
+	 */
+	public void setIdentityMappers(List<LocalIdentityMapper> mappers) {
+		this.mappers = mappers;
+	}
+
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext)
+			throws BeansException {
+		context = applicationContext;
+	}
+
+	@Override
+	public String getUsernameForPrincipal(UsernamePrincipal user) {
+		if (mappers == null)
+			return null;
+		for (LocalIdentityMapper m : mappers) {
+			String u = m.getUsernameForPrincipal(user);
+			if (u == null)
+				continue;
+			for (Entry<String, ? extends LocalIdentityMapper> entry : context
+					.getBeansOfType(m.getClass()).entrySet())
+				if (m == entry.getValue()) {
+					log.info("used " + entry.getKey() + " LIM to map " + user
+							+ " to " + u);
+					break;
+				}
+			return u;
+		}
+		return null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/ConstantIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/ConstantIDMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/ConstantIDMapper.java
new file mode 100644
index 0000000..bf48fc7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/ConstantIDMapper.java
@@ -0,0 +1,45 @@
+/*
+ */
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A trivial principal to user mapper that always uses the same ID.
+ * @author Donal Fellows
+ */
+public class ConstantIDMapper implements LocalIdentityMapper {
+	private String id;
+
+	/**
+	 * Sets what local user ID all users should be mapped to.
+	 * 
+	 * @param id
+	 *            The local user ID.
+	 */
+	public void setConstantId(String id) {
+		this.id = id;
+	}
+
+	@Override
+	public String getUsernameForPrincipal(UsernamePrincipal user) {
+		return id;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/NameIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/NameIDMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/NameIDMapper.java
new file mode 100644
index 0000000..9d11cfd
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/NameIDMapper.java
@@ -0,0 +1,63 @@
+/*
+ */
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */
+
+import static java.util.regex.Pattern.compile;
+
+import java.security.Principal;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A trivial identity mapper that just uses the name out of the
+ * {@link Principal}, or uses a regular expression to extract it from the string
+ * representation of the principal.
+ * 
+ * @author Donal Fellows
+ */
+public class NameIDMapper implements LocalIdentityMapper {
+	private Pattern pat;
+
+	/**
+	 * @param regexp
+	 *            The regular expression to use. The first capturing group
+	 *            within the RE will be the result of the extraction.
+	 * @throws PatternSyntaxException
+	 *             If the pattern is invalid.
+	 */
+	public void setRegexp(String regexp) throws PatternSyntaxException {
+		pat = compile(regexp);
+	}
+
+	@Override
+	public String getUsernameForPrincipal(UsernamePrincipal user) {
+		if (pat != null) {
+			Matcher m = pat.matcher(user.toString());
+			if (m.find() && m.groupCount() > 0) {
+				return m.group(1);
+			}
+			return null;
+		}
+		return user.getName();
+	}
+}


[41/42] incubator-taverna-server git commit: package org.apache.taverna.server.*

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunREST.java
index a04de46..9ee9471 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -26,11 +26,11 @@ import static javax.ws.rs.core.Response.status;
 import static org.apache.commons.logging.LogFactory.getLog;
 import static org.joda.time.format.ISODateTimeFormat.dateTime;
 import static org.joda.time.format.ISODateTimeFormat.dateTimeParser;
-import static org.taverna.server.master.common.Roles.SELF;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.common.Status.Initialized;
-import static org.taverna.server.master.common.Status.Operating;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.common.Roles.SELF;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.common.Status.Initialized;
+import static org.apache.taverna.server.master.common.Status.Operating;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import java.util.Date;
 
@@ -43,28 +43,28 @@ import org.apache.commons.logging.Log;
 import org.joda.time.DateTime;
 import org.apache.taverna.server.usagerecord.JobUsageRecord;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.RunBean;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.NotOwnerException;
-import org.taverna.server.master.exceptions.OverloadedException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.InteractionFeedREST;
-import org.taverna.server.master.rest.TavernaServerInputREST;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.rest.TavernaServerRunREST;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-import org.taverna.server.port_description.OutputDescription;
+import org.apache.taverna.server.master.api.RunBean;
+import org.apache.taverna.server.master.common.ProfileList;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.NotOwnerException;
+import org.apache.taverna.server.master.exceptions.OverloadedException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.rest.InteractionFeedREST;
+import org.apache.taverna.server.master.rest.TavernaServerInputREST;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST;
+import org.apache.taverna.server.master.rest.TavernaServerRunREST;
+import org.apache.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.port_description.OutputDescription;
 
 /**
  * RESTful interface to a single workflow run.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunSecurityREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunSecurityREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunSecurityREST.java
index 9dc69d7..7e98ee1 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunSecurityREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunSecurityREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,9 +21,9 @@ package org.taverna.server.master;
 import static java.util.UUID.randomUUID;
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.noContent;
-import static org.taverna.server.master.common.Status.Initialized;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.common.Status.Initialized;
+import static org.apache.taverna.server.master.common.Uri.secure;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import java.net.URI;
 import java.util.Map;
@@ -31,18 +31,18 @@ import java.util.Map;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
-import org.taverna.server.master.api.SecurityBean;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCredentialException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.master.api.SecurityBean;
+import org.apache.taverna.server.master.common.Credential;
+import org.apache.taverna.server.master.common.Permission;
+import org.apache.taverna.server.master.common.Trust;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.InvalidCredentialException;
+import org.apache.taverna.server.master.exceptions.NoCredentialException;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
 
 /**
  * RESTful interface to a single workflow run's security settings.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/SingleListenerREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/SingleListenerREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/SingleListenerREST.java
index 2c841cc..5987c67 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/SingleListenerREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/SingleListenerREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,23 +19,23 @@ package org.taverna.server.master;
  */
 
 import static java.util.Arrays.asList;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.common.Uri.secure;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import java.util.List;
 
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 
-import org.taverna.server.master.api.OneListenerBean;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
-import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.master.api.OneListenerBean;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
 
 /**
  * RESTful interface to a single listener attached to a workflow run.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServer.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServer.java
index 4844147..bf0842f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServer.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServer.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -28,16 +28,16 @@ import static javax.xml.ws.handler.MessageContext.HTTP_REQUEST_HEADERS;
 import static javax.xml.ws.handler.MessageContext.PATH_INFO;
 import static org.apache.commons.io.IOUtils.toByteArray;
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.TavernaServerSupport.PROV_BUNDLE;
-import static org.taverna.server.master.common.DirEntryReference.newInstance;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Roles.SELF;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.common.Status.Initialized;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.soap.DirEntry.convert;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.TavernaServerSupport.PROV_BUNDLE;
+import static org.apache.taverna.server.master.common.DirEntryReference.newInstance;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.Roles.ADMIN;
+import static org.apache.taverna.server.master.common.Roles.SELF;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.common.Status.Initialized;
+import static org.apache.taverna.server.master.common.Uri.secure;
+import static org.apache.taverna.server.master.soap.DirEntry.convert;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
@@ -69,59 +69,59 @@ import org.apache.commons.logging.Log;
 import org.apache.cxf.annotations.WSDLDocumentation;
 import org.apache.taverna.server.usagerecord.JobUsageRecord;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.SupportAware;
-import org.taverna.server.master.api.TavernaServerBean;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.common.InputDescription;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoCredentialException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.NotOwnerException;
-import org.taverna.server.master.exceptions.OverloadedException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.notification.NotificationEngine;
-import org.taverna.server.master.notification.atom.EventDAO;
-import org.taverna.server.master.rest.TavernaServerREST;
-import org.taverna.server.master.rest.TavernaServerREST.EnabledNotificationFabrics;
-import org.taverna.server.master.rest.TavernaServerREST.PermittedListeners;
-import org.taverna.server.master.rest.TavernaServerREST.PermittedWorkflows;
-import org.taverna.server.master.rest.TavernaServerREST.PolicyView;
-import org.taverna.server.master.rest.TavernaServerRunREST;
-import org.taverna.server.master.soap.DirEntry;
-import org.taverna.server.master.soap.FileContents;
-import org.taverna.server.master.soap.PermissionList;
-import org.taverna.server.master.soap.TavernaServerSOAP;
-import org.taverna.server.master.soap.WrappedWorkflow;
-import org.taverna.server.master.soap.ZippedDirectory;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-import org.taverna.server.port_description.OutputDescription;
+import org.apache.taverna.server.master.api.SupportAware;
+import org.apache.taverna.server.master.api.TavernaServerBean;
+import org.apache.taverna.server.master.common.Capability;
+import org.apache.taverna.server.master.common.Credential;
+import org.apache.taverna.server.master.common.DirEntryReference;
+import org.apache.taverna.server.master.common.InputDescription;
+import org.apache.taverna.server.master.common.Permission;
+import org.apache.taverna.server.master.common.ProfileList;
+import org.apache.taverna.server.master.common.RunReference;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Trust;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.common.version.Version;
+import org.apache.taverna.server.master.exceptions.BadPropertyValueException;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.InvalidCredentialException;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoCredentialException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.NotOwnerException;
+import org.apache.taverna.server.master.exceptions.OverloadedException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.factories.ListenerFactory;
+import org.apache.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.interfaces.DirectoryEntry;
+import org.apache.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.interfaces.Input;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.Policy;
+import org.apache.taverna.server.master.interfaces.RunStore;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.notification.NotificationEngine;
+import org.apache.taverna.server.master.notification.atom.EventDAO;
+import org.apache.taverna.server.master.rest.TavernaServerREST;
+import org.apache.taverna.server.master.rest.TavernaServerREST.EnabledNotificationFabrics;
+import org.apache.taverna.server.master.rest.TavernaServerREST.PermittedListeners;
+import org.apache.taverna.server.master.rest.TavernaServerREST.PermittedWorkflows;
+import org.apache.taverna.server.master.rest.TavernaServerREST.PolicyView;
+import org.apache.taverna.server.master.rest.TavernaServerRunREST;
+import org.apache.taverna.server.master.soap.DirEntry;
+import org.apache.taverna.server.master.soap.FileContents;
+import org.apache.taverna.server.master.soap.PermissionList;
+import org.apache.taverna.server.master.soap.TavernaServerSOAP;
+import org.apache.taverna.server.master.soap.WrappedWorkflow;
+import org.apache.taverna.server.master.soap.ZippedDirectory;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.port_description.OutputDescription;
 
 /**
  * The core implementation of the web application.
@@ -130,7 +130,7 @@ import org.taverna.server.port_description.OutputDescription;
  */
 @Path("/")
 @DeclareRoles({ USER, ADMIN })
-@WebService(endpointInterface = "org.taverna.server.master.soap.TavernaServerSOAP", serviceName = "TavernaServer", targetNamespace = SERVER_SOAP)
+@WebService(endpointInterface = "org.apache.taverna.server.master.soap.TavernaServerSOAP", serviceName = "TavernaServer", targetNamespace = SERVER_SOAP)
 @WSDLDocumentation("An instance of Taverna " + Version.JAVA + " Server.")
 public abstract class TavernaServer implements TavernaServerSOAP,
 		TavernaServerREST, TavernaServerBean {
@@ -1245,7 +1245,7 @@ public abstract class TavernaServer implements TavernaServerSOAP,
 	@CallCounted
 	@PerfLogged
 	@RolesAllowed(USER)
-	public org.taverna.server.port_description.InputDescription getRunInputDescriptor(
+	public org.apache.taverna.server.port_description.InputDescription getRunInputDescriptor(
 			String runName) throws UnknownRunException {
 		return cdBuilder.makeInputDescriptor(support.getRun(runName), null);
 	}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServerSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServerSupport.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServerSupport.java
index 533acf5..3c23c0d 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServerSupport.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServerSupport.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,9 +25,9 @@ import static java.lang.Math.min;
 import static org.apache.commons.logging.LogFactory.getLog;
 import static org.springframework.jmx.support.MetricType.COUNTER;
 import static org.springframework.jmx.support.MetricType.GAUGE;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+import static org.apache.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.apache.taverna.server.master.common.Roles.ADMIN;
+import static org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -61,37 +61,37 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserDetails;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.api.TavernaServerBean;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.factories.RunFactory;
-import org.taverna.server.master.identity.WorkflowInternalAuthProvider.WorkflowSelfAuthority;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.handler.T2FlowDocumentHandler;
-import org.taverna.server.master.utils.CapabilityLister;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.InvocationCounter;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.api.ManagementModel;
+import org.apache.taverna.server.master.api.TavernaServerBean;
+import org.apache.taverna.server.master.common.Capability;
+import org.apache.taverna.server.master.common.Permission;
+import org.apache.taverna.server.master.common.ProfileList;
+import org.apache.taverna.server.master.common.VersionedElement;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.common.version.Version;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoDestroyException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.factories.ListenerFactory;
+import org.apache.taverna.server.master.factories.RunFactory;
+import org.apache.taverna.server.master.identity.WorkflowInternalAuthProvider.WorkflowSelfAuthority;
+import org.apache.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.interfaces.Input;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.apache.taverna.server.master.interfaces.Policy;
+import org.apache.taverna.server.master.interfaces.RunStore;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler;
+import org.apache.taverna.server.master.utils.CapabilityLister;
+import org.apache.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.master.utils.InvocationCounter;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 import org.apache.taverna.scufl2.api.profiles.Profile;
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/Admin.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/Admin.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/Admin.java
index 03c0c8b..f7402b3 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/Admin.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/Admin.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.admin;
+package org.apache.taverna.server.master.admin;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,40 +18,40 @@ package org.taverna.server.master.admin;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.admin.Paths.ALLOW_NEW;
-import static org.taverna.server.master.admin.Paths.ARGS;
-import static org.taverna.server.master.admin.Paths.EXEC_WF;
-import static org.taverna.server.master.admin.Paths.EXITCODE;
-import static org.taverna.server.master.admin.Paths.FACTORIES;
-import static org.taverna.server.master.admin.Paths.GEN_PROV;
-import static org.taverna.server.master.admin.Paths.INVOKES;
-import static org.taverna.server.master.admin.Paths.JAR_FORKER;
-import static org.taverna.server.master.admin.Paths.JAR_WORKER;
-import static org.taverna.server.master.admin.Paths.JAVA;
-import static org.taverna.server.master.admin.Paths.LIFE;
-import static org.taverna.server.master.admin.Paths.LOG_EXN;
-import static org.taverna.server.master.admin.Paths.LOG_WFS;
-import static org.taverna.server.master.admin.Paths.OPERATING;
-import static org.taverna.server.master.admin.Paths.OP_LIMIT;
-import static org.taverna.server.master.admin.Paths.PASSFILE;
-import static org.taverna.server.master.admin.Paths.PERM_WF;
-import static org.taverna.server.master.admin.Paths.REG_HOST;
-import static org.taverna.server.master.admin.Paths.REG_JAR;
-import static org.taverna.server.master.admin.Paths.REG_POLL;
-import static org.taverna.server.master.admin.Paths.REG_PORT;
-import static org.taverna.server.master.admin.Paths.REG_WAIT;
-import static org.taverna.server.master.admin.Paths.ROOT;
-import static org.taverna.server.master.admin.Paths.RUNS;
-import static org.taverna.server.master.admin.Paths.RUN_LIMIT;
-import static org.taverna.server.master.admin.Paths.STARTUP;
-import static org.taverna.server.master.admin.Paths.TOTAL_RUNS;
-import static org.taverna.server.master.admin.Paths.URS;
-import static org.taverna.server.master.admin.Paths.UR_FILE;
-import static org.taverna.server.master.admin.Paths.USER;
-import static org.taverna.server.master.admin.Paths.USERS;
-import static org.taverna.server.master.admin.Types.JSON;
-import static org.taverna.server.master.admin.Types.PLAIN;
-import static org.taverna.server.master.admin.Types.XML;
+import static org.apache.taverna.server.master.admin.Paths.ALLOW_NEW;
+import static org.apache.taverna.server.master.admin.Paths.ARGS;
+import static org.apache.taverna.server.master.admin.Paths.EXEC_WF;
+import static org.apache.taverna.server.master.admin.Paths.EXITCODE;
+import static org.apache.taverna.server.master.admin.Paths.FACTORIES;
+import static org.apache.taverna.server.master.admin.Paths.GEN_PROV;
+import static org.apache.taverna.server.master.admin.Paths.INVOKES;
+import static org.apache.taverna.server.master.admin.Paths.JAR_FORKER;
+import static org.apache.taverna.server.master.admin.Paths.JAR_WORKER;
+import static org.apache.taverna.server.master.admin.Paths.JAVA;
+import static org.apache.taverna.server.master.admin.Paths.LIFE;
+import static org.apache.taverna.server.master.admin.Paths.LOG_EXN;
+import static org.apache.taverna.server.master.admin.Paths.LOG_WFS;
+import static org.apache.taverna.server.master.admin.Paths.OPERATING;
+import static org.apache.taverna.server.master.admin.Paths.OP_LIMIT;
+import static org.apache.taverna.server.master.admin.Paths.PASSFILE;
+import static org.apache.taverna.server.master.admin.Paths.PERM_WF;
+import static org.apache.taverna.server.master.admin.Paths.REG_HOST;
+import static org.apache.taverna.server.master.admin.Paths.REG_JAR;
+import static org.apache.taverna.server.master.admin.Paths.REG_POLL;
+import static org.apache.taverna.server.master.admin.Paths.REG_PORT;
+import static org.apache.taverna.server.master.admin.Paths.REG_WAIT;
+import static org.apache.taverna.server.master.admin.Paths.ROOT;
+import static org.apache.taverna.server.master.admin.Paths.RUNS;
+import static org.apache.taverna.server.master.admin.Paths.RUN_LIMIT;
+import static org.apache.taverna.server.master.admin.Paths.STARTUP;
+import static org.apache.taverna.server.master.admin.Paths.TOTAL_RUNS;
+import static org.apache.taverna.server.master.admin.Paths.URS;
+import static org.apache.taverna.server.master.admin.Paths.UR_FILE;
+import static org.apache.taverna.server.master.admin.Paths.USER;
+import static org.apache.taverna.server.master.admin.Paths.USERS;
+import static org.apache.taverna.server.master.admin.Types.JSON;
+import static org.apache.taverna.server.master.admin.Types.PLAIN;
+import static org.apache.taverna.server.master.admin.Types.XML;
 
 import java.io.IOException;
 import java.net.URI;
@@ -77,8 +77,8 @@ import javax.xml.bind.annotation.XmlType;
 
 import org.apache.cxf.jaxrs.model.wadl.Description;
 import org.apache.taverna.server.usagerecord.JobUsageRecord;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
+import org.apache.taverna.server.master.common.Uri;
+import org.apache.taverna.server.master.common.VersionedElement;
 
 /**
  * The administration interface for Taverna Server.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/AdminBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/AdminBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/AdminBean.java
index 0233cd5..4cef9d6 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/AdminBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/AdminBean.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.admin;
+package org.apache.taverna.server.master.admin;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,9 +23,9 @@ import static java.util.UUID.randomUUID;
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.noContent;
 import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.common.Roles.ADMIN;
+import static org.apache.taverna.server.master.common.Uri.secure;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -40,15 +40,15 @@ import javax.ws.rs.core.UriInfo;
 
 import org.apache.commons.io.IOUtils;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.exceptions.GeneralFailureException;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.identity.User;
-import org.taverna.server.master.identity.UserStoreAPI;
-import org.taverna.server.master.usage.UsageRecordRecorder;
-import org.taverna.server.master.utils.InvocationCounter;
-import org.taverna.server.master.worker.RunDBSupport;
-import org.taverna.server.master.worker.WorkerModel;
+import org.apache.taverna.server.master.api.ManagementModel;
+import org.apache.taverna.server.master.exceptions.GeneralFailureException;
+import org.apache.taverna.server.master.factories.ConfigurableRunFactory;
+import org.apache.taverna.server.master.identity.User;
+import org.apache.taverna.server.master.identity.UserStoreAPI;
+import org.apache.taverna.server.master.usage.UsageRecordRecorder;
+import org.apache.taverna.server.master.utils.InvocationCounter;
+import org.apache.taverna.server.master.worker.RunDBSupport;
+import org.apache.taverna.server.master.worker.WorkerModel;
 
 /**
  * The administration interface to Taverna Server.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/package-info.java
index 0a4174e..792ea72 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/package-info.java
@@ -13,7 +13,7 @@
 		@XmlNs(prefix = "admin", namespaceURI = ADMIN),
 		@XmlNs(prefix = "ur", namespaceURI = UR),
 		@XmlNs(prefix = "ds", namespaceURI = XSIG) })
-package org.taverna.server.master.admin;
+package org.apache.taverna.server.master.admin;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -32,14 +32,14 @@ package org.taverna.server.master.admin;
  */
 
 import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.UR;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.Namespaces.XSIG;
+import static org.apache.taverna.server.master.common.Namespaces.ADMIN;
+import static org.apache.taverna.server.master.common.Namespaces.FEED;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.Namespaces.UR;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Namespaces.XSIG;
 
 import javax.xml.bind.annotation.XmlNs;
 import javax.xml.bind.annotation.XmlSchema;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ContentTypes.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ContentTypes.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ContentTypes.java
index 2ad6063..5abcdd0 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ContentTypes.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ContentTypes.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/DirectoryBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/DirectoryBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/DirectoryBean.java
index 7cb1b7e..1f9b846 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/DirectoryBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/DirectoryBean.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -16,9 +16,9 @@ package org.taverna.server.master.api;
  * limitations under the License.
  */
 
-import org.taverna.server.master.rest.TavernaServerDirectoryREST;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.master.rest.TavernaServerDirectoryREST;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.utils.FilenameUtils;
 
 /**
  * Description of properties supported by {@link DirectoryREST}.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/FeedBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/FeedBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/FeedBean.java
index c977974..59e8040 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/FeedBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/FeedBean.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -16,8 +16,8 @@ package org.taverna.server.master.api;
  * limitations under the License.
  */
 
-import org.taverna.server.master.InteractionFeed;
-import org.taverna.server.master.interaction.InteractionFeedSupport;
+import org.apache.taverna.server.master.InteractionFeed;
+import org.apache.taverna.server.master.interaction.InteractionFeedSupport;
 
 /**
  * Description of properties supported by {@link InteractionFeed}.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/InputBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/InputBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/InputBean.java
index 17003e5..99c627d 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/InputBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/InputBean.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,13 +18,13 @@ package org.taverna.server.master.api;
 
 import javax.ws.rs.core.UriInfo;
 
-import org.taverna.server.master.ContentsDescriptorBuilder;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerInputREST;
-import org.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.master.ContentsDescriptorBuilder;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.TavernaServerInputREST;
+import org.apache.taverna.server.master.utils.FilenameUtils;
 
 /**
- * Description of properties supported by {@link org.taverna.server.master.InputREST}.
+ * Description of properties supported by {@link org.apache.taverna.server.master.InputREST}.
  * 
  * @author Donal Fellows
  */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenerPropertyBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenerPropertyBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenerPropertyBean.java
index 52a52f2..37b05c7 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenerPropertyBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenerPropertyBean.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -16,9 +16,9 @@ package org.taverna.server.master.api;
  * limitations under the License.
  */
 
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST;
 
 /**
  * Description of properties supported by {@link ListenerPropertyREST}.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenersBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenersBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenersBean.java
index 63035f7..9060af2 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenersBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenersBean.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -16,8 +16,8 @@ package org.taverna.server.master.api;
  * limitations under the License.
  */
 
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST;
 
 /**
  * Description of properties supported by {@link ListenersREST}.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ManagementModel.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ManagementModel.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ManagementModel.java
index dc02279..dc619ea 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ManagementModel.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ManagementModel.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/OneListenerBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/OneListenerBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/OneListenerBean.java
index f7a7134..0cb893c 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/OneListenerBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/OneListenerBean.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -16,9 +16,9 @@ package org.taverna.server.master.api;
  * limitations under the License.
  */
 
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
 
 /**
  * Description of properties supported by {@link InputREST}.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/RunBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/RunBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/RunBean.java
index 274d9f0..71c2057 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/RunBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/RunBean.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -16,11 +16,11 @@ package org.taverna.server.master.api;
  * limitations under the License.
  */
 
-import org.taverna.server.master.ContentsDescriptorBuilder;
-import org.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.ContentsDescriptorBuilder;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
 
 /**
- * Description of properties supported by {@link org.taverna.server.master.RunREST}.
+ * Description of properties supported by {@link org.apache.taverna.server.master.RunREST}.
  * 
  * @author Donal Fellows
  */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SecurityBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SecurityBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SecurityBean.java
index ddbc9b9..1ced5b5 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SecurityBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SecurityBean.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -16,9 +16,9 @@ package org.taverna.server.master.api;
  * limitations under the License.
  */
 
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.rest.TavernaServerSecurityREST;
 
 /**
  * Description of properties supported by {@link RunSecurityREST}.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SupportAware.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SupportAware.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SupportAware.java
index 117533f..e57f522 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SupportAware.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SupportAware.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -17,7 +17,7 @@ package org.taverna.server.master.api;
  */
 
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.TavernaServerSupport;
+import org.apache.taverna.server.master.TavernaServerSupport;
 
 /**
  * Indicates that this is a class that wants to be told by Spring about the

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/TavernaServerBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/TavernaServerBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/TavernaServerBean.java
index 8873857..4151479 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/TavernaServerBean.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/TavernaServerBean.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,17 +21,17 @@ package org.taverna.server.master.api;
 import javax.annotation.Nonnull;
 
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.ContentsDescriptorBuilder;
-import org.taverna.server.master.TavernaServerSupport;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.notification.NotificationEngine;
-import org.taverna.server.master.notification.atom.EventDAO;
-import org.taverna.server.master.rest.TavernaServerREST;
-import org.taverna.server.master.soap.TavernaServerSOAP;
-import org.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.master.ContentsDescriptorBuilder;
+import org.apache.taverna.server.master.TavernaServerSupport;
+import org.apache.taverna.server.master.interfaces.Policy;
+import org.apache.taverna.server.master.interfaces.RunStore;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.interfaces.UriBuilderFactory;
+import org.apache.taverna.server.master.notification.NotificationEngine;
+import org.apache.taverna.server.master.notification.atom.EventDAO;
+import org.apache.taverna.server.master.rest.TavernaServerREST;
+import org.apache.taverna.server.master.soap.TavernaServerSOAP;
+import org.apache.taverna.server.master.utils.FilenameUtils;
 
 /**
  * The methods of the webapp that are accessed by beans other than itself or

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/package-info.java
index 0966e24..cfffa6c 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/package-info.java
@@ -3,7 +3,7 @@
  * 
  * @author Donal Fellows
  */
-package org.taverna.server.master.api;
+package org.apache.taverna.server.master.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Capability.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Capability.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Capability.java
index 75f9549..a3cdb6f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Capability.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Capability.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Credential.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Credential.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Credential.java
index c6627da..0aabe57 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Credential.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Credential.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.common;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
 
 import java.io.Serializable;
 import java.net.URI;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/DirEntryReference.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/DirEntryReference.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/DirEntryReference.java
index 424e32a..5597f23 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/DirEntryReference.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/DirEntryReference.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.common;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
 
 import java.net.URI;
 
@@ -30,8 +30,8 @@ import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlValue;
 
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
+import org.apache.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.interfaces.DirectoryEntry;
 
 /**
  * A reference to something that is in a directory below the working directory

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/InputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/InputDescription.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/InputDescription.java
index b1eb55c..1e90c5b 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/InputDescription.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/InputDescription.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -27,8 +27,8 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlValue;
 
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.Input;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
 
 /**
  * A description of the inputs to a workflow, described using JAXB.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Namespaces.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Namespaces.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Namespaces.java
index d2035ee..c8386bb 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Namespaces.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Namespaces.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Permission.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Permission.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Permission.java
index 3e0a307..103edba 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Permission.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Permission.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlType;
 /**
  * Description of a permission to access a particular workflow run. Note that
  * users always have full access to their own runs, as does any user with the "
- * <tt>{@value org.taverna.server.master.common.Roles#ADMIN}</tt>" ability.
+ * <tt>{@value org.apache.taverna.server.master.common.Roles#ADMIN}</tt>" ability.
  * 
  * @author Donal Fellows
  */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/ProfileList.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/ProfileList.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/ProfileList.java
index d9b0a9e..8334804 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/ProfileList.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/ProfileList.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Roles.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Roles.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Roles.java
index bdcf876..7c3f9e3 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Roles.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Roles.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/RunReference.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/RunReference.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/RunReference.java
index cc80f60..1d6a9cc 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/RunReference.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/RunReference.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,9 +18,9 @@ package org.taverna.server.master.common;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.VersionedElement.VERSION;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.VersionedElement.VERSION;
 
 import java.net.URI;
 
@@ -36,7 +36,7 @@ import javax.xml.bind.annotation.XmlValue;
  * A reference to a single workflow run, described using JAXB.
  * 
  * @author Donal Fellows
- * @see org.taverna.server.master.interfaces.TavernaRun TavernaRun
+ * @see org.apache.taverna.server.master.interfaces.TavernaRun TavernaRun
  */
 @XmlRootElement
 @XmlType(name = "TavernaRun")

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Status.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Status.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Status.java
index 1aad4ef..c9c877a 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Status.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Status.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Trust.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Trust.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Trust.java
index c61e72a..787c8a3 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Trust.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Trust.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.common;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
 
 import java.io.Serializable;
 import java.security.cert.Certificate;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Uri.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Uri.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Uri.java
index ba0bb3c..c6570c2 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Uri.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Uri.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,7 +20,7 @@ package org.taverna.server.master.common;
 
 import static javax.ws.rs.core.UriBuilder.fromUri;
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
 
 import java.lang.reflect.Method;
 import java.net.URI;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/VersionedElement.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/VersionedElement.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/VersionedElement.java
index 735a72d..0ba82af 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/VersionedElement.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/VersionedElement.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,7 +19,7 @@ package org.taverna.server.master.common;
  */
 
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
 
 import java.io.IOException;
 import java.io.InputStream;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Workflow.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Workflow.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Workflow.java
index 3a7d5f7..e645545 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Workflow.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Workflow.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,10 +22,10 @@ import static javax.xml.bind.Marshaller.JAXB_ENCODING;
 import static javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT;
 import static javax.xml.bind.annotation.XmlAccessType.NONE;
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
+import static org.apache.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
+import static org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+import static org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
+import static org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -52,8 +52,8 @@ import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.parsers.DocumentBuilderFactory;
 
-import org.taverna.server.master.rest.handler.Scufl2DocumentHandler;
-import org.taverna.server.master.rest.handler.T2FlowDocumentHandler;
+import org.apache.taverna.server.master.rest.handler.Scufl2DocumentHandler;
+import org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.xml.sax.SAXException;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/package-info.java
index e000cef..8fb9e87 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/package-info.java
@@ -11,7 +11,7 @@
 		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
 		@XmlNs(prefix = "feed", namespaceURI = FEED),
 		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.common;
+package org.apache.taverna.server.master.common;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -30,12 +30,12 @@ package org.taverna.server.master.common;
  */
 
 import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Namespaces.ADMIN;
+import static org.apache.taverna.server.master.common.Namespaces.FEED;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.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/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/version/Version.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/version/Version.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/version/Version.java
index bd50db2..e5483cc 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/version/Version.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/version/Version.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.common.version;
+package org.apache.taverna.server.master.common.version;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,8 +18,8 @@ package org.taverna.server.master.common.version;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.version.Constants.PATCH;
-import static org.taverna.server.master.common.version.Constants.VERSION;
+import static org.apache.taverna.server.master.common.version.Constants.PATCH;
+import static org.apache.taverna.server.master.common.version.Constants.VERSION;
 
 /**
  * Common location for describing the version of the server.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/Default.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/Default.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/Default.java
index 679a5f4..1cdb67f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/Default.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/Default.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.defaults;
+package org.apache.taverna.server.master.defaults;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,8 +18,8 @@ package org.taverna.server.master.defaults;
  * limitations under the License.
  */
 
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.localworker.LocalWorkerState;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.localworker.LocalWorkerState;
 
 /**
  * This defines a collection of default values, collecting them from various

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/package-info.java
index 5585c77..cef0e13 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/defaults/package-info.java
@@ -2,7 +2,7 @@
  * This package contains information about the various default values supported by the server.
  * @author Donal Fellows
  */
-package org.taverna.server.master.defaults;
+package org.apache.taverna.server.master.defaults;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadInputPortNameException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadInputPortNameException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadInputPortNameException.java
index 64d07f0..b8bc21a 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadInputPortNameException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadInputPortNameException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadPropertyValueException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadPropertyValueException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadPropertyValueException.java
index 61bf740..9fb58e7 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadPropertyValueException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadPropertyValueException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadStateChangeException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadStateChangeException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadStateChangeException.java
index 152410f..2814588 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadStateChangeException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/BadStateChangeException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/FilesystemAccessException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/FilesystemAccessException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/FilesystemAccessException.java
index e0894e4..2e011ea 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/FilesystemAccessException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/FilesystemAccessException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/GeneralFailureException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/GeneralFailureException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/GeneralFailureException.java
index de3fab5..a1d35e6 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/GeneralFailureException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/GeneralFailureException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.exceptions;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
 
 import javax.xml.ws.WebFault;
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/InvalidCredentialException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/InvalidCredentialException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/InvalidCredentialException.java
index 7e00093..aadaf6e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/InvalidCredentialException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/InvalidCredentialException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCreateException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCreateException.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCreateException.java
index d665adb..19fe447 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCreateException.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/exceptions/NoCreateException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.exceptions;
+package org.apache.taverna.server.master.exceptions;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with



[20/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunFactoryConfiguration.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunFactoryConfiguration.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunFactoryConfiguration.java
new file mode 100644
index 0000000..642a6d6
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunFactoryConfiguration.java
@@ -0,0 +1,411 @@
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static org.springframework.jmx.support.MetricType.COUNTER;
+import static org.springframework.jmx.support.MetricType.GAUGE;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedMetric;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.master.factories.ConfigurableRunFactory;
+import org.taverna.server.master.localworker.LocalWorkerState;
+
+@ManagedResource(objectName = JMX_ROOT + "Factory", description = "The factory for runs.")
+public abstract class RunFactoryConfiguration implements ConfigurableRunFactory {
+	protected Log log = LogFactory.getLog("Taverna.Server.Worker");
+	protected LocalWorkerState state;
+	protected RunDBSupport runDB;
+	private int totalRuns = 0;
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	@Autowired(required = true)
+	@Order(0)
+	void setState(LocalWorkerState state) {
+		this.state = state;
+	}
+
+	@Autowired(required = true)
+	@Order(0)
+	void setRunDB(RunDBSupport runDB) {
+		this.runDB = runDB;
+	}
+
+	/**
+	 * Drop any current references to the registry of runs, and kill off that
+	 * process.
+	 */
+	protected abstract void reinitRegistry();
+
+	/**
+	 * Drop any current references to the run factory subprocess and kill it
+	 * off.
+	 */
+	protected abstract void reinitFactory();
+
+	/** Count the number of operating runs. */
+	protected abstract int operatingCount() throws Exception;
+
+	protected final synchronized void incrementRunCount() {
+		totalRuns++;
+	}
+
+	@Override
+	@ManagedAttribute(description = "Whether it is allowed to start a run executing.", currencyTimeLimit = 30)
+	public final boolean isAllowingRunsToStart() {
+		try {
+			return state.getOperatingLimit() > getOperatingCount();
+		} catch (Exception e) {
+			log.info("failed to get operating run count", e);
+			return false;
+		}
+	}
+
+	@Override
+	@ManagedAttribute(description = "The host holding the RMI registry to communicate via.")
+	public final String getRegistryHost() {
+		return state.getRegistryHost();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The host holding the RMI registry to communicate via.")
+	public final void setRegistryHost(String host) {
+		state.setRegistryHost(host);
+		reinitRegistry();
+		reinitFactory();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The port number of the RMI registry. Should not normally be set.")
+	public final int getRegistryPort() {
+		return state.getRegistryPort();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The port number of the RMI registry. Should not normally be set.")
+	public final void setRegistryPort(int port) {
+		state.setRegistryPort(port);
+		reinitRegistry();
+		reinitFactory();
+	}
+
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "What JAR do we use to start the RMI registry process?")
+	public final String getRmiRegistryJar() {
+		return state.getRegistryJar();
+	}
+
+	@Override
+	@ManagedAttribute(description = "What JAR do we use to start the RMI registry process?")
+	public final void setRmiRegistryJar(String rmiRegistryJar) {
+		state.setRegistryJar(rmiRegistryJar);
+		reinitRegistry();
+		reinitFactory();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The maximum number of simultaneous runs supported by the server.", currencyTimeLimit = 300)
+	public final int getMaxRuns() {
+		return state.getMaxRuns();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The maximum number of simultaneous runs supported by the server.", currencyTimeLimit = 300)
+	public final void setMaxRuns(int maxRuns) {
+		state.setMaxRuns(maxRuns);
+	}
+
+	/** @return How many minutes should a workflow live by default? */
+	@Override
+	@ManagedAttribute(description = "How many minutes should a workflow live by default?", currencyTimeLimit = 300)
+	public final int getDefaultLifetime() {
+		return state.getDefaultLifetime();
+	}
+
+	/**
+	 * Set how long a workflow should live by default.
+	 * 
+	 * @param defaultLifetime
+	 *            Default lifetime, in minutes.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many minutes should a workflow live by default?", currencyTimeLimit = 300)
+	public final void setDefaultLifetime(int defaultLifetime) {
+		state.setDefaultLifetime(defaultLifetime);
+	}
+
+	/**
+	 * @return How many milliseconds to wait between checks to see if a worker
+	 *         process has registered.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many milliseconds to wait between checks to see if a worker process has registered.", currencyTimeLimit = 300)
+	public final int getSleepTime() {
+		return state.getSleepMS();
+	}
+
+	/**
+	 * @param sleepTime
+	 *            How many milliseconds to wait between checks to see if a
+	 *            worker process has registered.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many milliseconds to wait between checks to see if a worker process has registered.", currencyTimeLimit = 300)
+	public final void setSleepTime(int sleepTime) {
+		state.setSleepMS(sleepTime);
+	}
+
+	/**
+	 * @return How many seconds to wait for a worker process to register itself.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many seconds to wait for a worker process to register itself.", currencyTimeLimit = 300)
+	public final int getWaitSeconds() {
+		return state.getWaitSeconds();
+	}
+
+	/**
+	 * @param seconds
+	 *            How many seconds to wait for a worker process to register
+	 *            itself.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many seconds to wait for a worker process to register itself.", currencyTimeLimit = 300)
+	public final void setWaitSeconds(int seconds) {
+		state.setWaitSeconds(seconds);
+	}
+
+	/** @return The script to run to start running a workflow. */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The script to run to start running a workflow.", currencyTimeLimit = 300)
+	public final String getExecuteWorkflowScript() {
+		return state.getExecuteWorkflowScript();
+	}
+
+	/**
+	 * @param executeWorkflowScript
+	 *            The script to run to start running a workflow.
+	 */
+	@Override
+	@ManagedAttribute(description = "The script to run to start running a workflow.", currencyTimeLimit = 300)
+	public final void setExecuteWorkflowScript(String executeWorkflowScript) {
+		state.setExecuteWorkflowScript(executeWorkflowScript);
+		reinitFactory();
+	}
+
+	/** @return The location of the JAR implementing the server worker processes. */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The location of the JAR implementing the server worker processes.")
+	public final String getServerWorkerJar() {
+		return state.getServerWorkerJar();
+	}
+
+	/**
+	 * @param serverWorkerJar
+	 *            The location of the JAR implementing the server worker
+	 *            processes.
+	 */
+	@Override
+	@ManagedAttribute(description = "The location of the JAR implementing the server worker processes.")
+	public final void setServerWorkerJar(String serverWorkerJar) {
+		state.setServerWorkerJar(serverWorkerJar);
+		reinitFactory();
+	}
+
+	/** @return The list of additional arguments used to make a worker process. */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The list of additional arguments used to make a worker process.", currencyTimeLimit = 300)
+	public final String[] getExtraArguments() {
+		return state.getExtraArgs();
+	}
+
+	/**
+	 * @param extraArguments
+	 *            The list of additional arguments used to make a worker
+	 *            process.
+	 */
+	@Override
+	@ManagedAttribute(description = "The list of additional arguments used to make a worker process.", currencyTimeLimit = 300)
+	public final void setExtraArguments(@Nonnull String[] extraArguments) {
+		state.setExtraArgs(extraArguments);
+		reinitFactory();
+	}
+
+	/** @return Which java executable to run. */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "Which java executable to run.", currencyTimeLimit = 300)
+	public final String getJavaBinary() {
+		return state.getJavaBinary();
+	}
+
+	/**
+	 * @param javaBinary
+	 *            Which java executable to run.
+	 */
+	@Override
+	@ManagedAttribute(description = "Which java executable to run.", currencyTimeLimit = 300)
+	public final void setJavaBinary(@Nonnull String javaBinary) {
+		state.setJavaBinary(javaBinary);
+		reinitFactory();
+	}
+
+	/**
+	 * @return A file containing a password to use when running a program as
+	 *         another user (e.g., with sudo).
+	 */
+	@Nullable
+	@Override
+	@ManagedAttribute(description = "A file containing a password to use when running a program as another user (e.g., with sudo).", currencyTimeLimit = 300)
+	public final String getPasswordFile() {
+		return state.getPasswordFile();
+	}
+
+	/**
+	 * @param passwordFile
+	 *            A file containing a password to use when running a program as
+	 *            another user (e.g., with sudo).
+	 */
+	@Override
+	@ManagedAttribute(description = "A file containing a password to use when running a program as another user (e.g., with sudo).", currencyTimeLimit = 300)
+	public final void setPasswordFile(@Nullable String passwordFile) {
+		state.setPasswordFile(passwordFile);
+		reinitFactory();
+	}
+
+	/**
+	 * @return The location of the JAR implementing the secure-fork process.
+	 */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The location of the JAR implementing the secure-fork process.", currencyTimeLimit = 300)
+	public final String getServerForkerJar() {
+		return state.getServerForkerJar();
+	}
+
+	/**
+	 * @param serverForkerJar
+	 *            The location of the JAR implementing the secure-fork process.
+	 */
+	@Override
+	@ManagedAttribute(description = "The location of the JAR implementing the secure-fork process.", currencyTimeLimit = 300)
+	public final void setServerForkerJar(String forkerJarFilename) {
+		state.setServerForkerJar(forkerJarFilename);
+		reinitFactory();
+	}
+
+	/**
+	 * @return How many times has a workflow run been spawned by this engine.
+	 *         Restarts reset this counter.
+	 */
+	@Override
+	@ManagedMetric(description = "How many times has a workflow run been spawned by this engine.", currencyTimeLimit = 10, metricType = COUNTER, category = "throughput")
+	public final synchronized int getTotalRuns() {
+		return totalRuns;
+	}
+
+	/**
+	 * @return How many checks were done for the worker process the last time a
+	 *         spawn was tried.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
+	public abstract int getLastStartupCheckCount();
+
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The names of the current runs.", currencyTimeLimit = 5)
+	public final String[] getCurrentRunNames() {
+		List<String> names = runDB.listRunNames();
+		return names.toArray(new String[names.size()]);
+	}
+
+	@Override
+	@ManagedAttribute(description = "What the factory subprocess's main RMI interface is registered as.", currencyTimeLimit = 60)
+	public abstract String getFactoryProcessName();
+
+	/**
+	 * @return What was the exit code from the last time the factory subprocess
+	 *         was killed?
+	 */
+	@Override
+	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
+	public abstract Integer getLastExitCode();
+
+	/**
+	 * @return The mapping of user names to RMI factory IDs.
+	 */
+	@Override
+	@ManagedAttribute(description = "The mapping of user names to RMI factory IDs.", currencyTimeLimit = 60)
+	public abstract String[] getFactoryProcessMapping();
+
+	@Override
+	@ManagedAttribute(description = "The maximum number of simultaneous operating runs supported by the server.", currencyTimeLimit = 300)
+	public final void setOperatingLimit(int operatingLimit) {
+		state.setOperatingLimit(operatingLimit);
+	}
+
+	@Override
+	@ManagedAttribute(description = "The maximum number of simultaneous operating runs supported by the server.", currencyTimeLimit = 300)
+	public final int getOperatingLimit() {
+		return state.getOperatingLimit();
+	}
+
+	/**
+	 * @return A count of the number of runs believed to actually be in the
+	 *         {@linkplain uk.org.taverna.server.master.common.Status#Operating
+	 *         operating} state.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	@Override
+	@ManagedMetric(description = "How many workflow runs are currently actually executing.", currencyTimeLimit = 10, metricType = GAUGE, category = "throughput")
+	public final int getOperatingCount() throws Exception {
+		return operatingCount();
+	}
+
+	@Override
+	@ManagedAttribute(description="Whether to tell a workflow to generate provenance bundles by default.")
+	public final void setGenerateProvenance(boolean genProv) {
+		state.setGenerateProvenance(genProv);
+	}
+
+	@Override
+	@ManagedAttribute(description="Whether to tell a workflow to generate provenance bundles by default.")
+	public final boolean getGenerateProvenance() {
+		return state.getGenerateProvenance();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegate.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegate.java
new file mode 100644
index 0000000..bb76f85
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegate.java
@@ -0,0 +1,662 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static java.lang.String.format;
+import static java.util.Arrays.fill;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.defaults.Default.CERTIFICATE_FIELD_NAMES;
+import static org.taverna.server.master.defaults.Default.CERTIFICATE_TYPE;
+import static org.taverna.server.master.defaults.Default.CREDENTIAL_FILE_SIZE_LIMIT;
+import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.rmi.RemoteException;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+import javax.security.auth.x500.X500Principal;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriBuilder;
+import javax.xml.ws.handler.MessageContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteSecurityContext;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Implementation of a security context.
+ * 
+ * @author Donal Fellows
+ */
+public abstract class SecurityContextDelegate implements TavernaSecurityContext {
+	Log log = LogFactory.getLog("Taverna.Server.Worker");
+	private final UsernamePrincipal owner;
+	private final List<Credential> credentials = new ArrayList<>();
+	private final List<Trust> trusted = new ArrayList<>();
+	private final RemoteRunDelegate run;
+	private final Object lock = new Object();
+	final SecurityContextFactory factory;
+
+	private transient Keystore keystore;
+	private transient Map<URI, String> uriToAliasMap;
+
+	/**
+	 * Initialise the context delegate.
+	 * 
+	 * @param run
+	 *            What workflow run is this for?
+	 * @param owner
+	 *            Who owns the workflow run?
+	 * @param factory
+	 *            What class built this object?
+	 */
+	protected SecurityContextDelegate(RemoteRunDelegate run,
+			UsernamePrincipal owner, SecurityContextFactory factory) {
+		this.run = run;
+		this.owner = owner;
+		this.factory = factory;
+	}
+
+	@Override
+	public SecurityContextFactory getFactory() {
+		return factory;
+	}
+
+	@Override
+	public UsernamePrincipal getOwner() {
+		return owner;
+	}
+
+	@Override
+	public Credential[] getCredentials() {
+		synchronized (lock) {
+			return credentials.toArray(new Credential[credentials.size()]);
+		}
+	}
+
+	/**
+	 * Get the human-readable name of a principal.
+	 * 
+	 * @param principal
+	 *            The principal being decoded.
+	 * @return A name.
+	 */
+	protected final String getPrincipalName(X500Principal principal) {
+		return factory.x500Utils.getName(principal, CERTIFICATE_FIELD_NAMES);
+	}
+
+	/**
+	 * Cause the current state to be flushed to the database.
+	 */
+	protected final void flushToDB() {
+		factory.db.flushToDisk(run);
+	}
+
+	@Override
+	public void addCredential(Credential toAdd) {
+		synchronized (lock) {
+			int idx = credentials.indexOf(toAdd);
+			if (idx != -1)
+				credentials.set(idx, toAdd);
+			else
+				credentials.add(toAdd);
+			flushToDB();
+		}
+	}
+
+	@Override
+	public void deleteCredential(Credential toDelete) {
+		synchronized (lock) {
+			credentials.remove(toDelete);
+			flushToDB();
+		}
+	}
+
+	@Override
+	public Trust[] getTrusted() {
+		synchronized (lock) {
+			return trusted.toArray(new Trust[trusted.size()]);
+		}
+	}
+
+	@Override
+	public void addTrusted(Trust toAdd) {
+		synchronized (lock) {
+			int idx = trusted.indexOf(toAdd);
+			if (idx != -1)
+				trusted.set(idx, toAdd);
+			else
+				trusted.add(toAdd);
+			flushToDB();
+		}
+	}
+
+	@Override
+	public void deleteTrusted(Trust toDelete) {
+		synchronized (lock) {
+			trusted.remove(toDelete);
+			flushToDB();
+		}
+	}
+
+	@Override
+	public abstract void validateCredential(Credential c)
+			throws InvalidCredentialException;
+
+	@Override
+	public void validateTrusted(Trust t) throws InvalidCredentialException {
+		InputStream contentsAsStream;
+		if (t.certificateBytes != null && t.certificateBytes.length > 0) {
+			contentsAsStream = new ByteArrayInputStream(t.certificateBytes);
+			t.certificateFile = null;
+		} else if (t.certificateFile == null
+				|| t.certificateFile.trim().isEmpty())
+			throw new InvalidCredentialException(
+					"absent or empty certificateFile");
+		else {
+			contentsAsStream = contents(t.certificateFile);
+			t.certificateBytes = null;
+		}
+		t.serverName = null;
+		if (t.fileType == null || t.fileType.trim().isEmpty())
+			t.fileType = CERTIFICATE_TYPE;
+		t.fileType = t.fileType.trim();
+		try {
+			t.loadedCertificates = CertificateFactory.getInstance(t.fileType)
+					.generateCertificates(contentsAsStream);
+			t.serverName = new ArrayList<>(t.loadedCertificates.size());
+			for (Certificate c : t.loadedCertificates)
+				t.serverName.add(getPrincipalName(((X509Certificate) c)
+						.getSubjectX500Principal()));
+		} catch (CertificateException e) {
+			throw new InvalidCredentialException(e);
+		} catch (ClassCastException e) {
+			// Do nothing; truncates the list of server names
+		}
+	}
+
+	@Override
+	public void initializeSecurityFromContext(SecurityContext securityContext)
+			throws Exception {
+		// This is how to get the info from Spring Security
+		Authentication auth = securityContext.getAuthentication();
+		if (auth == null)
+			return;
+		auth.getPrincipal();
+		// do nothing else in this implementation
+	}
+
+	@Override
+	public void initializeSecurityFromSOAPContext(MessageContext context) {
+		// do nothing in this implementation
+	}
+
+	@Override
+	public void initializeSecurityFromRESTContext(HttpHeaders context) {
+		// do nothing in this implementation
+	}
+
+	private UriBuilder getUB() {
+		return factory.uriSource.getRunUriBuilder(run);
+	}
+
+	private RunDatabaseDAO getDAO() {
+		return ((RunDatabase) factory.db).dao;
+	}
+
+	@Nullable
+	private List<X509Certificate> getCerts(URI uri) throws IOException,
+			GeneralSecurityException {
+		return factory.certFetcher.getTrustsForURI(uri);
+	}
+
+	private void installLocalPasswordCredential(List<Credential> credentials,
+			List<Trust> trusts) throws InvalidCredentialException, IOException,
+			GeneralSecurityException {
+		Credential.Password pw = new Credential.Password();
+		pw.id = "run:self";
+		pw.username = PREFIX + run.id;
+		pw.password = getDAO().getSecurityToken(run.id);
+		UriBuilder ub = getUB().segment("").fragment(factory.httpRealm);
+		pw.serviceURI = ub.build();
+		validateCredential(pw);
+		log.info("issuing self-referential credential for " + pw.serviceURI);
+		credentials.add(pw);
+		List<X509Certificate> myCerts = getCerts(pw.serviceURI);
+		if (myCerts != null && myCerts.size() > 0) {
+			Trust t = new Trust();
+			t.loadedCertificates = getCerts(pw.serviceURI);
+			trusts.add(t);
+		}
+	}
+
+	/**
+	 * Builds and transfers a keystore with suitable credentials to the back-end
+	 * workflow execution engine.
+	 * 
+	 * @throws GeneralSecurityException
+	 *             If the manipulation of the keystore, keys or certificates
+	 *             fails.
+	 * @throws IOException
+	 *             If there are problems building the data (should not happen).
+	 * @throws RemoteException
+	 *             If the conveyancing fails.
+	 */
+	@Override
+	public final void conveySecurity() throws GeneralSecurityException,
+			IOException, ImplementationException {
+		RemoteSecurityContext rc = run.run.getSecurityContext();
+
+		List<Trust> trusted = new ArrayList<>(this.trusted);
+		this.trusted.clear();
+		List<Credential> credentials = new ArrayList<>(this.credentials);
+		this.credentials.clear();
+
+		try {
+			installLocalPasswordCredential(credentials, trusted);
+		} catch (Exception e) {
+			log.warn("failed to construct local credential: "
+					+ "interaction service will fail", e);
+		}
+
+		char[] password = null;
+		try {
+			password = generateNewPassword();
+
+			log.info("constructing merged keystore");
+			Truststore truststore = new Truststore(password);
+			Keystore keystore = new Keystore(password);
+			Map<URI, String> uriToAliasMap = new HashMap<>();
+			int trustedCount = 0, keyCount = 0;
+
+			synchronized (lock) {
+				try {
+					for (Trust t : trusted) {
+						if (t == null || t.loadedCertificates == null)
+							continue;
+						for (Certificate cert : t.loadedCertificates)
+							if (cert != null) {
+								truststore.addCertificate(cert);
+								trustedCount++;
+							}
+					}
+
+					this.uriToAliasMap = uriToAliasMap;
+					this.keystore = keystore;
+					for (Credential c : credentials) {
+						addCredentialToKeystore(c);
+						keyCount++;
+					}
+				} finally {
+					this.uriToAliasMap = null;
+					this.keystore = null;
+					credentials.clear();
+					trusted.clear();
+					flushToDB();
+				}
+			}
+
+			byte[] trustbytes = null, keybytes = null;
+			try {
+				trustbytes = truststore.serialize();
+				keybytes = keystore.serialize();
+
+				// Now we've built the security information, ship it off...
+
+				log.info("transfering merged truststore with " + trustedCount
+						+ " entries");
+				rc.setTruststore(trustbytes);
+
+				log.info("transfering merged keystore with " + keyCount
+						+ " entries");
+				rc.setKeystore(keybytes);
+			} finally {
+				if (trustbytes != null)
+					fill(trustbytes, (byte) 0);
+				if (keybytes != null)
+					fill(keybytes, (byte) 0);
+			}
+			rc.setPassword(password);
+
+			log.info("transferring serviceURL->alias map with "
+					+ uriToAliasMap.size() + " entries");
+			rc.setUriToAliasMap(uriToAliasMap);
+		} finally {
+			if (password != null)
+				fill(password, ' ');
+		}
+
+		synchronized (lock) {
+			conveyExtraSecuritySettings(rc);
+		}
+	}
+
+	/**
+	 * Hook that allows additional information to be conveyed to the remote run.
+	 * 
+	 * @param remoteSecurityContext
+	 *            The remote resource that information would be passed to.
+	 * @throws IOException
+	 *             If anything goes wrong with the communication.
+	 */
+	protected void conveyExtraSecuritySettings(
+			RemoteSecurityContext remoteSecurityContext) throws IOException {
+		// Does nothing by default; overrideable
+	}
+
+	/**
+	 * @return A new password with a reasonable level of randomness.
+	 */
+	protected final char[] generateNewPassword() {
+		return randomUUID().toString().toCharArray();
+	}
+
+	/**
+	 * Adds a credential to the current keystore.
+	 * 
+	 * @param alias
+	 *            The alias to create within the keystore.
+	 * @param c
+	 *            The key-pair.
+	 * @throws KeyStoreException
+	 */
+	protected final void addKeypairToKeystore(String alias, Credential c)
+			throws KeyStoreException {
+		if (c.loadedKey == null)
+			throw new KeyStoreException("critical: credential was not verified");
+		if (uriToAliasMap.containsKey(c.serviceURI))
+			log.warn("duplicate URI in alias mapping: " + c.serviceURI);
+		keystore.addKey(alias, c.loadedKey, c.loadedTrustChain);
+		uriToAliasMap.put(c.serviceURI, alias);
+	}
+
+	/**
+	 * Adds a credential to the current keystore.
+	 * 
+	 * @param c
+	 *            The credential to add.
+	 * @throws KeyStoreException
+	 */
+	public abstract void addCredentialToKeystore(Credential c)
+			throws KeyStoreException;
+
+	/**
+	 * Read a file up to {@value #FILE_SIZE_LIMIT}kB in size.
+	 * 
+	 * @param name
+	 *            The path name of the file, relative to the context run's
+	 *            working directory.
+	 * @return A stream of the file's contents.
+	 * @throws InvalidCredentialException
+	 *             If anything goes wrong.
+	 */
+	final InputStream contents(String name) throws InvalidCredentialException {
+		try {
+			File f = (File) factory.fileUtils.getDirEntry(run, name);
+			long size = f.getSize();
+			if (size > CREDENTIAL_FILE_SIZE_LIMIT * 1024)
+				throw new InvalidCredentialException(CREDENTIAL_FILE_SIZE_LIMIT
+						+ "kB limit hit");
+			return new ByteArrayInputStream(f.getContents(0, (int) size));
+		} catch (NoDirectoryEntryException | FilesystemAccessException e) {
+			throw new InvalidCredentialException(e);
+		} catch (ClassCastException e) {
+			throw new InvalidCredentialException("not a file", e);
+		}
+	}
+
+	@Override
+	public Set<String> getPermittedDestroyers() {
+		return run.getDestroyers();
+	}
+
+	@Override
+	public void setPermittedDestroyers(Set<String> destroyers) {
+		run.setDestroyers(destroyers);
+	}
+
+	@Override
+	public Set<String> getPermittedUpdaters() {
+		return run.getWriters();
+	}
+
+	@Override
+	public void setPermittedUpdaters(Set<String> updaters) {
+		run.setWriters(updaters);
+	}
+
+	@Override
+	public Set<String> getPermittedReaders() {
+		return run.getReaders();
+	}
+
+	@Override
+	public void setPermittedReaders(Set<String> readers) {
+		run.setReaders(readers);
+	}
+
+	/**
+	 * Reinstall the credentials and the trust extracted from serialization to
+	 * the database.
+	 * 
+	 * @param credentials
+	 *            The credentials to reinstall.
+	 * @param trust
+	 *            The trusted certificates to reinstall.
+	 */
+	void setCredentialsAndTrust(Credential[] credentials, Trust[] trust) {
+		synchronized (lock) {
+			this.credentials.clear();
+			if (credentials != null)
+				for (Credential c : credentials)
+					try {
+						validateCredential(c);
+						this.credentials.add(c);
+					} catch (InvalidCredentialException e) {
+						log.warn("failed to revalidate credential: " + c, e);
+					}
+			this.trusted.clear();
+			if (trust != null)
+				for (Trust t : trust)
+					try {
+						validateTrusted(t);
+						this.trusted.add(t);
+					} catch (InvalidCredentialException e) {
+						log.warn("failed to revalidate trust assertion: " + t,
+								e);
+					}
+		}
+	}
+
+	static class SecurityStore {
+		private KeyStore ks;
+		private char[] password;
+
+		SecurityStore(char[] password) throws GeneralSecurityException {
+			this.password = password.clone();
+			ks = KeyStore.getInstance("UBER", "BC");
+			try {
+				ks.load(null, this.password);
+			} catch (IOException e) {
+				throw new GeneralSecurityException(
+						"problem initializing blank truststore", e);
+			}
+		}
+
+		final synchronized void setCertificate(String alias, Certificate c)
+				throws KeyStoreException {
+			if (ks == null)
+				throw new IllegalStateException("store already written");
+			ks.setCertificateEntry(alias, c);
+		}
+
+		final synchronized void setKey(String alias, Key key, Certificate[] trustChain)
+				throws KeyStoreException {
+			if (ks == null)
+				throw new IllegalStateException("store already written");
+			ks.setKeyEntry(alias, key, password, trustChain);
+		}
+
+		final synchronized byte[] serialize(boolean logIt)
+				throws GeneralSecurityException {
+			if (ks == null)
+				throw new IllegalStateException("store already written");
+			try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
+				ks.store(stream, password);
+				if (logIt)
+					LogFactory.getLog("Taverna.Server.Worker").debug(
+							"serialized UBER/BC truststore (size: " + ks.size()
+									+ ") with password \""
+									+ new String(password) + "\"");
+				return stream.toByteArray();
+			} catch (IOException e) {
+				throw new GeneralSecurityException(
+						"problem serializing keystore", e);
+			} finally {
+				ks = null;
+				fill(password, ' ');
+			}
+		}
+
+		@Override
+		protected final void finalize() {
+			fill(password, ' ');
+			ks = null;
+		}
+	}
+
+	/**
+	 * A trust store that can only be added to or serialized. Only trusted
+	 * certificates can be placed in it.
+	 * 
+	 * @author Donal Fellows
+	 */
+	class Truststore extends SecurityStore {
+		Truststore(char[] password) throws GeneralSecurityException {
+			super(password);
+		}
+
+		/**
+		 * Add a trusted certificate to the truststore. No certificates can be
+		 * added after the truststore is serialized.
+		 * 
+		 * @param cert
+		 *            The certificate (typically belonging to a root CA) to add.
+		 * @throws KeyStoreException
+		 *             If anything goes wrong.
+		 */
+		public void addCertificate(Certificate cert) throws KeyStoreException {
+			X509Certificate c = (X509Certificate) cert;
+			String alias = format("trustedcert#%s#%s#%s",
+					getPrincipalName(c.getSubjectX500Principal()),
+					getPrincipalName(c.getIssuerX500Principal()),
+					factory.x500Utils.getSerial(c));
+			setCertificate(alias, c);
+			if (log.isDebugEnabled() && factory.logSecurityDetails)
+				log.debug("added cert with alias \"" + alias + "\" of type "
+						+ c.getClass().getCanonicalName());
+		}
+
+		/**
+		 * Get the byte serialization of this truststore. This can only be
+		 * fetched exactly once.
+		 * 
+		 * @return The serialization.
+		 * @throws GeneralSecurityException
+		 *             If anything goes wrong.
+		 */
+		public byte[] serialize() throws GeneralSecurityException {
+			return serialize(log.isDebugEnabled() && factory.logSecurityDetails);
+		}
+	}
+
+	/**
+	 * A key store that can only be added to or serialized. Only keys can be
+	 * placed in it.
+	 * 
+	 * @author Donal Fellows
+	 */
+	class Keystore extends SecurityStore {
+		Keystore(char[] password) throws GeneralSecurityException {
+			super(password);
+		}
+
+		/**
+		 * Add a key to the keystore. No keys can be added after the keystore is
+		 * serialized.
+		 * 
+		 * @param alias
+		 *            The alias of the key.
+		 * @param key
+		 *            The secret/private key to add.
+		 * @param trustChain
+		 *            The trusted certificate chain of the key. Should be
+		 *            <tt>null</tt> for secret keys.
+		 * @throws KeyStoreException
+		 *             If anything goes wrong.
+		 */
+		public void addKey(String alias, Key key, Certificate[] trustChain)
+				throws KeyStoreException {
+			setKey(alias, key, trustChain);
+			if (log.isDebugEnabled() && factory.logSecurityDetails)
+				log.debug("added key with alias \"" + alias + "\" of type "
+						+ key.getClass().getCanonicalName());
+		}
+
+		/**
+		 * Get the byte serialization of this keystore. This can only be fetched
+		 * exactly once.
+		 * 
+		 * @return The serialization.
+		 * @throws GeneralSecurityException
+		 *             If anything goes wrong.
+		 */
+		public byte[] serialize() throws GeneralSecurityException {
+			return serialize(log.isDebugEnabled() && factory.logSecurityDetails);
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegateImpl.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegateImpl.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegateImpl.java
new file mode 100644
index 0000000..ef29b55
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextDelegateImpl.java
@@ -0,0 +1,311 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static java.lang.String.format;
+import static javax.xml.ws.handler.MessageContext.HTTP_REQUEST_HEADERS;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.rmi.RemoteException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.spec.SecretKeySpec;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.ws.handler.MessageContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.taverna.server.localworker.remote.RemoteSecurityContext;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.utils.UsernamePrincipal;
+import org.taverna.server.master.utils.X500Utils;
+
+/**
+ * Factoring out of the part of the security context handling that actually
+ * deals with the different types of credentials.
+ * 
+ * @author Donal Fellows
+ */
+class SecurityContextDelegateImpl extends SecurityContextDelegate {
+	private static final char USERNAME_PASSWORD_SEPARATOR = '\u0000';
+	private static final String USERNAME_PASSWORD_KEY_ALGORITHM = "DUMMY";
+	/** What passwords are encoded as. */
+	private static final Charset UTF8 = Charset.forName("UTF-8");
+
+	private X500Utils x500Utils;
+
+	/**
+	 * Initialise the context delegate.
+	 * 
+	 * @param run
+	 *            What workflow run is this for?
+	 * @param owner
+	 *            Who owns the workflow run?
+	 * @param factory
+	 *            What class built this object?
+	 */
+	protected SecurityContextDelegateImpl(RemoteRunDelegate run,
+			UsernamePrincipal owner, SecurityContextFactory factory) {
+		super(run, owner, factory);
+		this.x500Utils = factory.x500Utils;
+	}
+
+	@Override
+	public void validateCredential(Credential c)
+			throws InvalidCredentialException {
+		try {
+			if (c instanceof Credential.Password)
+				validatePasswordCredential((Credential.Password) c);
+			else if (c instanceof Credential.KeyPair)
+				validateKeyCredential((Credential.KeyPair) c);
+			else
+				throw new InvalidCredentialException("unknown credential type");
+		} catch (InvalidCredentialException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new InvalidCredentialException(e);
+		}
+	}
+
+	@Override
+	public void addCredentialToKeystore(Credential c) throws KeyStoreException {
+		try {
+			if (c instanceof Credential.Password)
+				addUserPassToKeystore((Credential.Password) c);
+			else if (c instanceof Credential.KeyPair)
+				addKeypairToKeystore((Credential.KeyPair) c);
+			else
+				throw new KeyStoreException("unknown credential type");
+		} catch (KeyStoreException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new KeyStoreException(e);
+		}
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	/**
+	 * Tests whether the given username+password credential descriptor is valid.
+	 * If it is invalid, an exception will be thrown describing what the problem
+	 * is. Validation mainly consists of listing what the username is.
+	 * 
+	 * @param passwordDescriptor
+	 *            The credential descriptor to validate.
+	 * @throws InvalidCredentialException
+	 *             If the username is empty. NB: the password may be empty!
+	 *             That's legal (if unwise).
+	 */
+	protected void validatePasswordCredential(
+			Credential.Password passwordDescriptor)
+			throws InvalidCredentialException {
+		if (passwordDescriptor.username == null
+				|| passwordDescriptor.username.trim().isEmpty())
+			throw new InvalidCredentialException("absent or empty username");
+		if (passwordDescriptor.serviceURI == null)
+			throw new InvalidCredentialException("absent service URI");
+		String keyToSave = passwordDescriptor.username
+				+ USERNAME_PASSWORD_SEPARATOR + passwordDescriptor.password;
+		passwordDescriptor.loadedKey = encodeKey(keyToSave);
+		passwordDescriptor.loadedTrustChain = null;
+	}
+
+	private static Key encodeKey(String key) {
+		return new SecretKeySpec(key.getBytes(UTF8),
+				USERNAME_PASSWORD_KEY_ALGORITHM);
+	}
+
+	/**
+	 * Adds a username/password credential pair to the current keystore.
+	 * 
+	 * @param userpassCredential
+	 *            The username and password.
+	 * @throws KeyStoreException
+	 */
+	protected void addUserPassToKeystore(Credential.Password userpassCredential)
+			throws KeyStoreException {
+		String alias = format("password#%s",
+				userpassCredential.serviceURI.toASCIIString());
+		addKeypairToKeystore(alias, userpassCredential);
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	/**
+	 * Tests whether the given key-pair credential descriptor is valid. If it is
+	 * invalid, an exception will be thrown describing what the problem is.
+	 * 
+	 * @param keypairDescriptor
+	 *            The descriptor to validate.
+	 * @throws InvalidCredentialException
+	 *             If the descriptor is invalid
+	 * @throws KeyStoreException
+	 *             If we don't understand the keystore type or the contents of
+	 *             the keystore
+	 * @throws NoSuchAlgorithmException
+	 *             If the keystore is of a known type but we can't comprehend
+	 *             its security
+	 * @throws CertificateException
+	 *             If the keystore does not include enough information about the
+	 *             trust chain of the keypair
+	 * @throws UnrecoverableKeyException
+	 *             If we can't get the key out of the keystore
+	 * @throws IOException
+	 *             If we can't read the keystore for prosaic reasons (e.g., file
+	 *             absent)
+	 */
+	protected void validateKeyCredential(Credential.KeyPair keypairDescriptor)
+			throws InvalidCredentialException, KeyStoreException,
+			NoSuchAlgorithmException, CertificateException, IOException,
+			UnrecoverableKeyException {
+		if (keypairDescriptor.credentialName == null
+				|| keypairDescriptor.credentialName.trim().isEmpty())
+			throw new InvalidCredentialException(
+					"absent or empty credentialName");
+
+		InputStream contentsAsStream;
+		if (keypairDescriptor.credentialBytes != null
+				&& keypairDescriptor.credentialBytes.length > 0) {
+			contentsAsStream = new ByteArrayInputStream(
+					keypairDescriptor.credentialBytes);
+			keypairDescriptor.credentialFile = null;
+		} else if (keypairDescriptor.credentialFile == null
+				|| keypairDescriptor.credentialFile.trim().isEmpty())
+			throw new InvalidCredentialException(
+					"absent or empty credentialFile");
+		else {
+			contentsAsStream = contents(keypairDescriptor.credentialFile);
+			keypairDescriptor.credentialBytes = new byte[0];
+		}
+		if (keypairDescriptor.fileType == null
+				|| keypairDescriptor.fileType.trim().isEmpty())
+			keypairDescriptor.fileType = KeyStore.getDefaultType();
+		keypairDescriptor.fileType = keypairDescriptor.fileType.trim();
+
+		KeyStore ks = KeyStore.getInstance(keypairDescriptor.fileType);
+		char[] password = keypairDescriptor.unlockPassword.toCharArray();
+		ks.load(contentsAsStream, password);
+
+		try {
+			keypairDescriptor.loadedKey = ks.getKey(
+					keypairDescriptor.credentialName, password);
+		} catch (UnrecoverableKeyException ignored) {
+			keypairDescriptor.loadedKey = ks.getKey(
+					keypairDescriptor.credentialName, new char[0]);
+		}
+		if (keypairDescriptor.loadedKey == null)
+			throw new InvalidCredentialException(
+					"no such credential in key store");
+		keypairDescriptor.loadedTrustChain = ks
+				.getCertificateChain(keypairDescriptor.credentialName);
+		if (keypairDescriptor.loadedTrustChain == null
+				|| keypairDescriptor.loadedTrustChain.length == 0)
+			throw new InvalidCredentialException(
+					"could not establish trust chain for credential");
+	}
+
+	/**
+	 * Adds a key-pair to the current keystore.
+	 * 
+	 * @param c
+	 *            The key-pair.
+	 * @throws KeyStoreException
+	 */
+	protected void addKeypairToKeystore(Credential.KeyPair c)
+			throws KeyStoreException {
+		X509Certificate subjectCert = (X509Certificate) c.loadedTrustChain[0];
+		String alias = format("keypair#%s#%s#%s",
+				getPrincipalName(subjectCert.getSubjectX500Principal()),
+				getPrincipalName(subjectCert.getIssuerX500Principal()),
+				x500Utils.getSerial(subjectCert));
+		addKeypairToKeystore(alias, c);
+	}
+}
+
+/**
+ * Special subclass that adds support for HELIO project security tokens.
+ * 
+ * @author Donal Fellows
+ */
+class HelioSecurityContextDelegateImpl extends SecurityContextDelegateImpl {
+	/**
+	 * Initialise the context delegate.
+	 * 
+	 * @param run
+	 *            What workflow run is this for?
+	 * @param owner
+	 *            Who owns the workflow run?
+	 * @param factory
+	 *            What class built this object?
+	 */
+	protected HelioSecurityContextDelegateImpl(RemoteRunDelegate run,
+			UsernamePrincipal owner, SecurityContextFactory factory) {
+		super(run, owner, factory);
+	}
+
+	private Log log = LogFactory.getLog("Taverna.Server.Worker");
+	/** The name of the HTTP header holding the CIS token. */
+	private static final String HELIO_CIS_TOKEN = "X-Helio-CIS";
+	private transient String helioToken;
+
+	@Override
+	public void initializeSecurityFromSOAPContext(MessageContext context) {
+		// does nothing
+		@SuppressWarnings("unchecked")
+		Map<String, List<String>> headers = (Map<String, List<String>>) context
+				.get(HTTP_REQUEST_HEADERS);
+		if (factory.supportHelioToken && headers.containsKey(HELIO_CIS_TOKEN))
+			helioToken = headers.get(HELIO_CIS_TOKEN).get(0);
+	}
+
+	@Override
+	public void initializeSecurityFromRESTContext(HttpHeaders context) {
+		// does nothing
+		MultivaluedMap<String, String> headers = context.getRequestHeaders();
+		if (factory.supportHelioToken && headers.containsKey(HELIO_CIS_TOKEN))
+			helioToken = headers.get(HELIO_CIS_TOKEN).get(0);
+	}
+
+	@Override
+	protected void conveyExtraSecuritySettings(RemoteSecurityContext rc)
+			throws RemoteException {
+		try {
+			if (factory.supportHelioToken && helioToken != null) {
+				if (factory.logSecurityDetails)
+					log.info("transfering HELIO CIS token: " + helioToken);
+				rc.setHelioToken(helioToken);
+			}
+		} finally {
+			helioToken = null;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextFactory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextFactory.java
new file mode 100644
index 0000000..1d485d8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SecurityContextFactory.java
@@ -0,0 +1,167 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static java.security.Security.addProvider;
+import static java.security.Security.getProvider;
+import static java.security.Security.removeProvider;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
+
+import java.io.Serializable;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.logging.Log;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.beans.factory.annotation.Value;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.utils.CertificateChainFetcher;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.master.utils.UsernamePrincipal;
+import org.taverna.server.master.utils.X500Utils;
+
+/**
+ * Singleton factory. Really is a singleton (and is also very trivial); the
+ * singleton-ness is just about limiting the number of instances of this around
+ * even when lots of serialization is going on.
+ * 
+ * @see Serializable
+ * @author Donal Fellows
+ */
+public class SecurityContextFactory implements
+		org.taverna.server.master.interfaces.SecurityContextFactory {
+	private static final long serialVersionUID = 12345678987654321L;
+	private static SecurityContextFactory instance;
+	transient RunDBSupport db;
+	transient FilenameUtils fileUtils;
+	transient X500Utils x500Utils;
+	transient UriBuilderFactory uriSource;
+	transient CertificateChainFetcher certFetcher;
+	transient String httpRealm;
+	private transient PasswordIssuer passwordIssuer;
+	private transient BouncyCastleProvider provider;
+
+	/**
+	 * Whether to support HELIO CIS tokens.
+	 */
+	@Value("${helio.cis.enableTokenPassing}")
+	boolean supportHelioToken;
+
+	/**
+	 * Whether to log the details of security (passwords, etc).
+	 */
+	@Value("${log.security.details}")
+	boolean logSecurityDetails;
+
+	private Log log() {
+		return getLog("Taverna.Server.Worker.Security");
+	}
+
+	private void installAsInstance(SecurityContextFactory handle) {
+		instance = handle;
+	}
+
+	@PreDestroy
+	void removeAsSingleton() {
+		installAsInstance(null);
+		try {
+			if (provider != null)
+				removeProvider(provider.getName());
+		} catch (SecurityException e) {
+			log().warn(
+					"failed to remove BouncyCastle security provider; "
+							+ "might be OK if configured in environment", e);
+		}
+	}
+
+	@PostConstruct
+	void setAsSingleton() {
+		installAsInstance(this);
+		if (getProvider(PROVIDER_NAME) == null)
+			try {
+				provider = new BouncyCastleProvider();
+				if (addProvider(provider) == -1)
+					provider = null;
+			} catch (SecurityException e) {
+				log().warn(
+						"failed to install BouncyCastle security provider; "
+								+ "might be OK if already configured", e);
+				provider = null;
+			}
+	}
+
+	@Required
+	public void setRunDatabase(RunDBSupport db) {
+		this.db = db;
+	}
+
+	@Required
+	public void setCertificateFetcher(CertificateChainFetcher fetcher) {
+		this.certFetcher = fetcher;
+	}
+
+	@Required
+	public void setFilenameConverter(FilenameUtils fileUtils) {
+		this.fileUtils = fileUtils;
+	}
+
+	@Required
+	public void setX500Utils(X500Utils x500Utils) {
+		this.x500Utils = x500Utils;
+	}
+
+	@Required
+	public void setUriSource(UriBuilderFactory uriSource) {
+		this.uriSource = uriSource;
+	}
+
+	@Required
+	public void setHttpRealm(String realm) {
+		this.httpRealm = realm; //${http.realmName}
+	}
+
+	@Required
+	public void setPasswordIssuer(PasswordIssuer issuer) {
+		this.passwordIssuer = issuer;
+	}
+
+	@Override
+	public SecurityContextDelegate create(TavernaRun run,
+			UsernamePrincipal owner) throws Exception {
+		Log log = log();
+		if (log.isDebugEnabled())
+			log.debug("constructing security context delegate for " + owner);
+		RemoteRunDelegate rrd = (RemoteRunDelegate) run;
+		return new HelioSecurityContextDelegateImpl(rrd, owner, this);
+	}
+
+	private Object readResolve() {
+		if (instance == null)
+			installAsInstance(this);
+		return instance;
+	}
+
+	public String issueNewPassword() {
+		return passwordIssuer.issue();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
new file mode 100644
index 0000000..f9f4d16
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
@@ -0,0 +1,77 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.defaults.Default.NOTIFY_MESSAGE_FORMAT;
+
+import java.text.MessageFormat;
+
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * Completion notifier that sends messages by email.
+ * 
+ * @author Donal Fellows
+ */
+public class SimpleFormattedCompletionNotifier implements CompletionNotifier {
+	@Required
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * @param subject
+	 *            The subject of the notification email.
+	 */
+	@Required
+	public void setSubject(String subject) {
+		this.subject = subject;
+	}
+
+	/**
+	 * @param messageFormat
+	 *            The template for the body of the message to send. Parameter #0
+	 *            will be substituted with the ID of the job, and parameter #1
+	 *            will be substituted with the exit code.
+	 */
+	public void setMessageFormat(String messageFormat) {
+		this.format = new MessageFormat(messageFormat);
+	}
+
+	private String name;
+	private String subject;
+	private MessageFormat format = new MessageFormat(NOTIFY_MESSAGE_FORMAT);
+
+	@Override
+	public String makeCompletionMessage(String name, RemoteRunDelegate run,
+			int code) {
+		return format.format(new Object[] { name, code });
+	}
+
+	@Override
+	public String makeMessageSubject(String name, RemoteRunDelegate run,
+			int code) {
+		return subject;
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/VelocityCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/VelocityCompletionNotifier.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/VelocityCompletionNotifier.java
new file mode 100644
index 0000000..a81e610
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/VelocityCompletionNotifier.java
@@ -0,0 +1,121 @@
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import java.io.StringWriter;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.common.version.Version;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+
+public class VelocityCompletionNotifier implements CompletionNotifier {
+	private String subject;
+	private VelocityEngine engine;
+	private Template template;
+	private String name;
+	private String templateName;
+	private UriBuilderFactory ubf;
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @param subject
+	 *            The subject of the notification email.
+	 */
+	@Required
+	public void setSubject(String subject) {
+		this.subject = subject;
+	}
+
+	/**
+	 * @param engine
+	 *            The configured Apache Velocity engine.
+	 */
+	@Required
+	public void setVelocityEngine(VelocityEngine engine) {
+		this.engine = engine;
+	}
+
+	/**
+	 * @param uriBuilderFactory
+	 *            The configured URI builder factory.
+	 */
+	@Required
+	public void setUriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
+		this.ubf = uriBuilderFactory;
+	}
+
+	/**
+	 * @param name
+	 *            The name of the template.
+	 */
+	@Required
+	public void setName(String name) {
+		this.name = name;
+		this.templateName = getClass().getName() + "_" + name + ".vtmpl";
+	}
+
+	private Template getTemplate() {
+		if (template == null)
+			synchronized(this) {
+				if (template == null)
+					template = engine.getTemplate(templateName);
+			}
+		return template;
+	}
+
+	@Override
+	public String makeCompletionMessage(String name, RemoteRunDelegate run,
+			int code) {
+		VelocityContext ctxt = new VelocityContext();
+		ctxt.put("id", name);
+		ctxt.put("uriBuilder", ubf.getRunUriBuilder(run));
+		ctxt.put("name", run.getName());
+		ctxt.put("creationTime", run.getCreationTimestamp());
+		ctxt.put("startTime", run.getStartTimestamp());
+		ctxt.put("finishTime", run.getFinishTimestamp());
+		ctxt.put("expiryTime", run.getExpiry());
+		ctxt.put("serverVersion", Version.JAVA);
+		for (Listener l : run.getListeners())
+			if (l.getName().equals("io")) {
+				for (String p : l.listProperties())
+					try {
+						ctxt.put("prop_" + p, l.getProperty(p));
+					} catch (NoListenerException e) {
+						// Ignore...
+					}
+				break;
+			}
+		StringWriter sw = new StringWriter();
+		getTemplate().merge(ctxt, sw);
+		return sw.toString();
+	}
+
+	@Override
+	public String makeMessageSubject(String name, RemoteRunDelegate run,
+			int code) {
+		return subject;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/WorkerModel.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/WorkerModel.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/WorkerModel.java
new file mode 100644
index 0000000..510c8d0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/WorkerModel.java
@@ -0,0 +1,216 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import java.net.URI;
+import java.util.List;
+
+import org.taverna.server.master.common.Status;
+
+/**
+ * Profile of the getters and setters in a worker system. Ensures that the
+ * persisted state matches the public view on the state model at least fairly
+ * closely.
+ * 
+ * @author Donal Fellows
+ */
+public interface WorkerModel extends PolicyLimits {
+
+	/**
+	 * @param defaultLifetime
+	 *            how long a workflow run should live by default, in minutes.
+	 */
+	public abstract void setDefaultLifetime(int defaultLifetime);
+
+	/**
+	 * @return how long a workflow run should live by default, in minutes.
+	 */
+	public abstract int getDefaultLifetime();
+
+	/**
+	 * @param maxRuns
+	 *            the maximum number of extant workflow runs
+	 */
+	public abstract void setMaxRuns(int maxRuns);
+
+	/**
+	 * @param factoryProcessNamePrefix
+	 *            the prefix used for factory processes in RMI
+	 */
+	public abstract void setFactoryProcessNamePrefix(
+			String factoryProcessNamePrefix);
+
+	/**
+	 * @return the prefix used for factory processes in RMI
+	 */
+	public abstract String getFactoryProcessNamePrefix();
+
+	/**
+	 * @param executeWorkflowScript
+	 *            the script to run to actually run a workflow
+	 */
+	public abstract void setExecuteWorkflowScript(String executeWorkflowScript);
+
+	/**
+	 * @return the script to run to actually run a workflow
+	 */
+	public abstract String getExecuteWorkflowScript();
+
+	/**
+	 * @param extraArgs
+	 *            the extra arguments to pass into the workflow runner
+	 */
+	public abstract void setExtraArgs(String[] extraArgs);
+
+	/**
+	 * @return the extra arguments to pass into the workflow runner
+	 */
+	public abstract String[] getExtraArgs();
+
+	/**
+	 * @param waitSeconds
+	 *            the number of seconds to wait for subprocesses to start
+	 */
+	public abstract void setWaitSeconds(int waitSeconds);
+
+	/**
+	 * @return the number of seconds to wait for subprocesses to start
+	 */
+	public abstract int getWaitSeconds();
+
+	/**
+	 * @param sleepMS
+	 *            milliseconds to wait between polling for a started
+	 *            subprocess's status
+	 */
+	public abstract void setSleepMS(int sleepMS);
+
+	/**
+	 * @return milliseconds to wait between polling for a started subprocess's
+	 *         status
+	 */
+	public abstract int getSleepMS();
+
+	/**
+	 * @param serverWorkerJar
+	 *            the full path name of the file system access worker
+	 *            subprocess's implementation JAR
+	 */
+	public abstract void setServerWorkerJar(String serverWorkerJar);
+
+	/**
+	 * @return the full path name of the file system access worker subprocess's
+	 *         implementation JAR
+	 */
+	public abstract String getServerWorkerJar();
+
+	/**
+	 * @param javaBinary
+	 *            the full path name to the Java binary to use
+	 */
+	public abstract void setJavaBinary(String javaBinary);
+
+	/**
+	 * @return the full path name to the Java binary to use
+	 */
+	public abstract String getJavaBinary();
+
+	/**
+	 * @param registryPort
+	 *            what port is the RMI registry on
+	 */
+	public abstract void setRegistryPort(int registryPort);
+
+	/**
+	 * @return what port is the RMI registry on
+	 */
+	public abstract int getRegistryPort();
+
+	/**
+	 * @param registryHost
+	 *            what host (network interface) is the RMI registry on
+	 */
+	public abstract void setRegistryHost(String registryHost);
+
+	/**
+	 * @return what host (network interface) is the RMI registry on
+	 */
+	public abstract String getRegistryHost();
+
+	/**
+	 * @param serverForkerJar
+	 *            the full path name of the impersonation engine's
+	 *            implementation JAR
+	 */
+	public abstract void setServerForkerJar(String serverForkerJar);
+
+	/**
+	 * @return the full path name of the impersonation engine's implementation
+	 *         JAR
+	 */
+	public abstract String getServerForkerJar();
+
+	/**
+	 * @param passwordFile
+	 *            the full path name of a file containing a password to use with
+	 *            sudo (or empty for none)
+	 */
+	public abstract void setPasswordFile(String passwordFile);
+
+	/**
+	 * @return the full path name of a file containing a password to use with
+	 *         sudo (or empty for none)
+	 */
+	public abstract String getPasswordFile();
+
+	/**
+	 * @param operatingLimit
+	 *            the maximum number of runs in the
+	 *            {@linkplain Status#Operating operating} state at once
+	 */
+	public abstract void setOperatingLimit(int operatingLimit);
+
+	@Override
+	void setPermittedWorkflowURIs(List<URI> permittedWorkflows);
+
+	/**
+	 * @return the full path name of the RMI registry subprocess's
+	 *         implementation JAR
+	 */
+	String getRegistryJar();
+
+	/**
+	 * @param rmiRegistryJar
+	 *            the full path name of the RMI registry subprocess's
+	 *            implementation JAR
+	 */
+	void setRegistryJar(String rmiRegistryJar);
+
+	/**
+	 * @return whether a run should generate provenance information by default
+	 */
+	boolean getGenerateProvenance();
+
+	/**
+	 * @param generateProvenance
+	 *            whether a run should generate provenance information by
+	 *            default
+	 */
+	void setGenerateProvenance(boolean generateProvenance);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/package-info.java
new file mode 100644
index 0000000..e96b794
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/package-info.java
@@ -0,0 +1,23 @@
+/*
+ */
+/**
+ * A Taverna Server back-end that works by forking off workflow executors.
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java
deleted file mode 100644
index 051a037..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static eu.medsea.util.MimeUtil.getMimeType;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.common.Uri.secure;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.port_description.AbsentValue;
-import org.taverna.server.port_description.AbstractPortDescription;
-import org.taverna.server.port_description.AbstractValue;
-import org.taverna.server.port_description.ErrorValue;
-import org.taverna.server.port_description.InputDescription;
-import org.taverna.server.port_description.InputDescription.InputPort;
-import org.taverna.server.port_description.LeafValue;
-import org.taverna.server.port_description.ListValue;
-import org.taverna.server.port_description.OutputDescription;
-import org.taverna.server.port_description.OutputDescription.OutputPort;
-
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-import org.apache.taverna.scufl2.api.core.Workflow;
-import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
-import org.apache.taverna.scufl2.api.port.OutputWorkflowPort;
-
-/**
- * A class that is used to build descriptions of the contents of a workflow
- * run's filesystem.
- * 
- * @author Donal Fellows
- */
-public class ContentsDescriptorBuilder {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private FilenameUtils fileUtils;
-	private UriBuilderFactory uriBuilderFactory;
-
-	@Required
-	public void setUriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
-		this.uriBuilderFactory = uriBuilderFactory;
-	}
-
-	@Required
-	public void setFileUtils(FilenameUtils fileUtils) {
-		this.fileUtils = fileUtils;
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	private Workflow fillInFromWorkflow(TavernaRun run, UriBuilder ub,
-			AbstractPortDescription portDesc) throws IOException {
-		WorkflowBundle bundle = run.getWorkflow().getScufl2Workflow();
-		bundle.getMainWorkflow().getInputPorts();
-		portDesc.fillInBaseData(bundle.getMainWorkflow()
-				.getIdentifier().toString(), run.getId(), ub.build());
-		return bundle.getMainWorkflow();
-	}
-
-	/**
-	 * Computes the depth of value in a descriptor.
-	 * 
-	 * @param value
-	 *            The value description to characterise.
-	 * @return Its depth (i.e., the depth of the port outputting the value) or
-	 *         <tt>null</tt> if that is impossible to determine.
-	 */
-	private Integer computeDepth(AbstractValue value) {
-		if (value instanceof ListValue) {
-			int mv = 1;
-			for (AbstractValue v : ((ListValue) value).contents) {
-				Integer d = computeDepth(v);
-				if (d != null && mv <= d)
-					mv = d + 1;
-			}
-			return mv;
-		} else if (value instanceof LeafValue || value instanceof ErrorValue)
-			return 0;
-		else
-			return null;
-	}
-
-	/**
-	 * Build a description of a leaf value.
-	 * 
-	 * @param file
-	 *            The file representing the value.
-	 * @return A value descriptor.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	private LeafValue constructLeafValue(File file)
-			throws FilesystemAccessException {
-		LeafValue v = new LeafValue();
-		v.fileName = file.getFullName();
-		v.byteLength = file.getSize();
-		try {
-			byte[] head = file.getContents(0, 1024);
-			v.contentType = getMimeType(new ByteArrayInputStream(head));
-		} catch (Exception e) {
-			v.contentType = APPLICATION_OCTET_STREAM_TYPE.toString();
-		}
-		return v;
-	}
-
-	/**
-	 * Build a description of an error value.
-	 * 
-	 * @param file
-	 *            The file representing the error.
-	 * @return A value descriptor.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	private ErrorValue constructErrorValue(File file)
-			throws FilesystemAccessException {
-		ErrorValue v = new ErrorValue();
-		v.fileName = file.getFullName();
-		v.byteLength = file.getSize();
-		return v;
-	}
-
-	/**
-	 * Build a description of a list value.
-	 * 
-	 * @param dir
-	 *            The directory representing the list.
-	 * @param ub
-	 *            The factory for URIs.
-	 * @return A value descriptor.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	private ListValue constructListValue(Directory dir, UriBuilder ub)
-			throws FilesystemAccessException {
-		ListValue v = new ListValue();
-		v.length = 0;
-		Set<DirectoryEntry> contents = new HashSet<>(dir.getContents());
-		Iterator<DirectoryEntry> it = contents.iterator();
-		while (it.hasNext())
-			if (!it.next().getName().matches("^[0-9]+([.].*)?$"))
-				it.remove();
-		for (int i = 1; !contents.isEmpty(); i++) {
-			String exact = Integer.toString(i);
-			AbstractValue subval = constructValue(contents, ub, exact);
-			v.contents.add(subval);
-			if (!(subval instanceof AbsentValue)) {
-				v.length = i;
-				String pfx = i + ".";
-				for (DirectoryEntry de : contents)
-					if (de.getName().equals(exact)
-							|| de.getName().startsWith(pfx)) {
-						contents.remove(de);
-						break;
-					}
-			}
-		}
-		return v;
-	}
-
-	/**
-	 * Build a value description.
-	 * 
-	 * @param parentContents
-	 *            The contents of the parent directory.
-	 * @param ub
-	 *            The factory for URIs.
-	 * @param name
-	 *            The name of the value's file/directory representative.
-	 * @return A value descriptor.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	private AbstractValue constructValue(
-			Collection<DirectoryEntry> parentContents, UriBuilder ub,
-			String name) throws FilesystemAccessException {
-		String error = name + ".error";
-		String prefix = name + ".";
-		for (DirectoryEntry entry : parentContents) {
-			AbstractValue av;
-			if (entry.getName().equals(error) && entry instanceof File) {
-				av = constructErrorValue((File) entry);
-			} else if (!entry.getName().equals(name)
-					&& !entry.getName().startsWith(prefix))
-				continue;
-			else if (entry instanceof File)
-				av = constructLeafValue((File) entry);
-			else
-				av = constructListValue((Directory) entry, ub);
-			String fullPath = entry.getFullName().replaceFirst("^/", "");
-			av.href = ub.clone().path(fullPath).build();
-			return av;
-		}
-		return new AbsentValue();
-	}
-
-	/**
-	 * Construct a description of the outputs of a workflow run.
-	 * 
-	 * @param run
-	 *            The workflow run whose outputs are to be described.
-	 * @param ui
-	 *            The origin for URIs.
-	 * @return The description, which can be serialized to XML.
-	 * @throws FilesystemAccessException
-	 *             If something goes wrong reading the directories.
-	 * @throws NoDirectoryEntryException
-	 *             If something goes wrong reading the directories.
-	 */
-	public OutputDescription makeOutputDescriptor(TavernaRun run, UriInfo ui)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		OutputDescription descriptor = new OutputDescription();
-		try {
-			UriBuilder ub = getRunUriBuilder(run, ui);
-			Workflow dataflow = fillInFromWorkflow(run, ub, descriptor);
-			Collection<DirectoryEntry> outs = null;
-			ub = ub.path("wd/{path}");
-			for (OutputWorkflowPort output : dataflow.getOutputPorts()) {
-				OutputPort p = descriptor.addPort(output.getName());
-				if (run.getOutputBaclavaFile() == null) {
-					if (outs == null)
-						outs = fileUtils.getDirectory(run, "out").getContents();
-					p.output = constructValue(outs, ub, p.name);
-					p.depth = computeDepth(p.output);
-				}
-			}
-		} catch (IOException e) {
-			log.info("failure in conversion to .scufl2", e);
-		}
-		return descriptor;
-	}
-
-	private UriBuilder getRunUriBuilder(TavernaRun run, UriInfo ui) {
-		if (ui == null)
-			return secure(uriBuilderFactory.getRunUriBuilder(run));
-		else
-			return secure(fromUri(ui.getAbsolutePath().toString()
-					.replaceAll("/(out|in)put/?$", "")));
-	}
-
-	/**
-	 * Constructs input descriptions.
-	 * 
-	 * @param run
-	 *            The run to build for.
-	 * @param ui
-	 *            The mechanism for building URIs.
-	 * @return The description of the <i>expected</i> inputs of the run.
-	 */
-	public InputDescription makeInputDescriptor(TavernaRun run, UriInfo ui) {
-		InputDescription desc = new InputDescription();
-		try {
-			UriBuilder ub = getRunUriBuilder(run, ui);
-			Workflow workflow = fillInFromWorkflow(run, ub, desc);
-			ub = ub.path("input/{name}");
-			for (InputWorkflowPort port : workflow.getInputPorts()) {
-				InputPort in = desc.addPort(port.getName());
-				in.href = ub.build(in.name);
-				try {
-					in.depth = port.getDepth();
-				} catch (NumberFormatException ex) {
-					in.depth = null;
-				}
-			}
-		} catch (IOException e) {
-			log.info("failure in conversion to .scufl2", e);
-		}
-		return desc;
-	}
-}


[08/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java
deleted file mode 100644
index 745876d..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- */
-package org.taverna.server.master.soap;
-/*
- * 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.
- */
-
-import static javax.xml.bind.annotation.XmlAccessType.NONE;
-import static org.apache.commons.io.IOUtils.closeQuietly;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-
-import javax.activation.DataHandler;
-import javax.activation.DataSource;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlMimeType;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.common.Workflow;
-
-import org.apache.taverna.scufl2.api.io.ReaderException;
-import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
-import org.apache.taverna.scufl2.api.io.WriterException;
-
-/**
- * An MTOM-capable description of how to transfer the contents of a file.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "WorkflowReference")
-@XmlAccessorType(NONE)
-public class WrappedWorkflow {
-	@XmlMimeType("application/octet-stream")
-	// JAXB bug: must be this
-	public DataHandler workflowData;
-	Workflow workflow;
-
-	/**
-	 * Initialize the contents of this descriptor from the given file and
-	 * content type.
-	 * 
-	 * @param workflow
-	 *            The workflow that is to be reported.
-	 */
-	public void setWorkflow(Workflow workflow) {
-		workflowData = new DataHandler(new WorkflowSource(workflow));
-	}
-
-	@XmlTransient
-	public Workflow getWorkflow() throws IOException {
-		if (workflow != null)
-			return workflow;
-		try {
-			return new Workflow(new WorkflowBundleIO().readBundle(
-					workflowData.getInputStream(), null));
-		} catch (ReaderException e) {
-			throw new IOException("problem converting to scufl2 bundle", e);
-		}
-	}
-}
-
-/**
- * A data source that knows how to deliver a workflow.
- * 
- * @author Donal Fellows
- */
-class WorkflowSource implements DataSource {
-	WorkflowSource(Workflow workflow) {
-		this.wf = workflow;
-		this.io = new WorkflowBundleIO();
-	}
-
-	Workflow wf;
-	final WorkflowBundleIO io;
-
-	@Override
-	public String getContentType() {
-		return wf.getPreferredContentType().getContentType();
-	}
-
-	@Override
-	public String getName() {
-		switch (wf.getPreferredContentType()) {
-		case SCUFL2:
-			return "workflow.scufl2";
-		case T2FLOW:
-			return "workflow.t2flow";
-		default:
-			return "workflow";
-		}
-	}
-
-	@Override
-	public InputStream getInputStream() throws IOException {
-		PipedInputStream is = new PipedInputStream();
-		final OutputStream os = new PipedOutputStream(is);
-		new Worker() {
-			@Override
-			public void doWork() throws WriterException, IOException {
-				io.writeBundle(wf.getScufl2Workflow(), os, wf
-						.getPreferredContentType().getContentType());
-			}
-
-			@Override
-			public void doneWork() {
-				closeQuietly(os);
-			}
-		};
-		return is;
-	}
-
-	@Override
-	public OutputStream getOutputStream() throws IOException {
-		final PipedInputStream is = new PipedInputStream();
-		OutputStream os = new PipedOutputStream(is);
-		new Worker() {
-			@Override
-			public void doWork() throws IOException, ReaderException {
-				wf = new Workflow(io.readBundle(is, null));
-			}
-
-			@Override
-			public void doneWork() {
-				closeQuietly(is);
-			}
-		};
-		return os;
-	}
-
-	static abstract class Worker extends Thread {
-		public Worker() {
-			setDaemon(true);
-			start();
-		}
-
-		public abstract void doWork() throws Exception;
-
-		public abstract void doneWork();
-
-		@Override
-		public void run() {
-			try {
-				doWork();
-			} catch (Exception e) {
-				// do nothing.
-			} finally {
-				doneWork();
-			}
-		}
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java
deleted file mode 100644
index 5b2d261..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- */
-package org.taverna.server.master.soap;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import javax.activation.DataHandler;
-import javax.activation.DataSource;
-import javax.activation.UnsupportedDataTypeException;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlMimeType;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.Directory;
-
-/**
- * An MTOM-capable description of how to transfer the zipped contents of a
- * directory.
- * 
- * @author Donal Fellows
- * @see Directory#getContentsAsZip()
- */
-@XmlType(name = "ZippedDirectory")
-public class ZippedDirectory {
-	@XmlElement
-	public String name;
-	@XmlMimeType("application/octet-stream")
-	// JAXB bug: must be this
-	public DataHandler fileData;
-
-	public ZippedDirectory() {
-	}
-
-	/**
-	 * Initialise the contents of this descriptor from the given directory.
-	 * 
-	 * @param dir
-	 *            The directory that is to be reported.
-	 */
-	public ZippedDirectory(Directory dir) {
-		name = dir.getFullName();
-		fileData = new DataHandler(new ZipSource(dir));
-	}
-}
-
-/**
- * A data source that knows how to communicate with the Taverna Server back-end.
- * 
- * @author Donal Fellows
- */
-class ZipSource implements DataSource {
-	ZipSource(Directory d) {
-		this.d = d;
-	}
-
-	private final Directory d;
-
-	@Override
-	public String getContentType() {
-		return APPLICATION_ZIP_TYPE.toString();
-	}
-
-	@Override
-	public String getName() {
-		return d.getName();
-	}
-
-	@Override
-	public InputStream getInputStream() throws IOException {
-		try {
-			return d.getContentsAsZip();
-		} catch (FilesystemAccessException e) {
-			throw new IOException(e);
-		}
-	}
-
-	@Override
-	public OutputStream getOutputStream() throws IOException {
-		throw new UnsupportedDataTypeException();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java
deleted file mode 100644
index cd753b7..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- */
-/**
- * This package contains the SOAP interface to Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER_SOAP, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "port", namespaceURI = DATA),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.soap;
-/*
- * 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.
- */
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.port_description.Namespaces.DATA;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java
deleted file mode 100644
index b1f0602..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- */
-package org.taverna.server.master.usage;
-/*
- * 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.
- */
-
-import java.util.Date;
-
-import javax.jdo.annotations.Column;
-import javax.jdo.annotations.Index;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.PrimaryKey;
-import javax.jdo.annotations.Queries;
-import javax.jdo.annotations.Query;
-import javax.xml.bind.JAXBException;
-
-import org.apache.taverna.server.usagerecord.JobUsageRecord;
-
-/**
- * A usage record as recorded in the database.
- * 
- * @author Donal Fellows
- */
-@PersistenceCapable(table = "USAGE_RECORD_LOG", schema = "UR", cacheable = "true")
-@Queries({ @Query(name = "allByDate", value = "SELECT USAGE_RECORD FROM UR.USAGE_RECORD_LOG ORDER BY CREATE_DATE", resultClass = String.class, unmodifiable = "true", unique = "false", language = "SQL") })
-public class UsageRecord {
-	/**
-	 * Create an empty usage record database entry.
-	 */
-	public UsageRecord() {
-	}
-
-	/**
-	 * Create a usage record database entry that is populated from the given UR.
-	 * 
-	 * @param usageRecord
-	 *            The originating usage record.
-	 * @throws JAXBException
-	 *             If deserialization of the record fails.
-	 */
-	public UsageRecord(String usageRecord) throws JAXBException {
-		JobUsageRecord jur = JobUsageRecord.unmarshal(usageRecord);
-		setUsageRecord(usageRecord);
-		setCreateDate(jur.getRecordIdentity().getCreateTime()
-				.toGregorianCalendar().getTime());
-		setId(jur.getRecordIdentity().getRecordId());
-		setUserid(jur.getUserIdentity().get(0).getLocalUserId());
-	}
-
-	/**
-	 * Create a usage record database entry that is populated from the given UR.
-	 * 
-	 * @param usageRecord
-	 *            The originating usage record.
-	 * @throws JAXBException
-	 *             If serialization of the record fails.
-	 */
-	public UsageRecord(JobUsageRecord usageRecord) throws JAXBException {
-		setUsageRecord(usageRecord.marshal());
-		setCreateDate(usageRecord.getRecordIdentity().getCreateTime()
-				.toGregorianCalendar().getTime());
-		setId(usageRecord.getRecordIdentity().getRecordId());
-		setUserid(usageRecord.getUserIdentity().get(0).getLocalUserId());
-	}
-
-	@PrimaryKey
-	@Column(name = "ID", length = 40)
-	private String id;
-
-	@Persistent
-	@Index(name = "USERID_IDX")
-	@Column(name = "USERID", length = 24)
-	private String userid;
-
-	@Persistent
-	@Index(name = "CREATE_IDX")
-	@Column(name = "CREATE_DATE")
-	private Date createDate;
-
-	@Persistent
-	@Column(name = "USAGE_RECORD", jdbcType = "CLOB")
-	private String usageRecord;
-
-	public String getId() {
-		return id;
-	}
-
-	public void setId(String id) {
-		this.id = id;
-	}
-
-	public String getUserid() {
-		return userid;
-	}
-
-	public void setUserid(String userid) {
-		this.userid = userid;
-	}
-
-	public Date getCreateDate() {
-		return createDate;
-	}
-
-	public void setCreateDate(Date createDate) {
-		this.createDate = createDate;
-	}
-
-	public String getUsageRecord() {
-		return usageRecord;
-	}
-
-	public void setUsageRecord(String usageRecord) {
-		this.usageRecord = usageRecord;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java
deleted file mode 100644
index 18aeb3b..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- */
-package org.taverna.server.master.usage;
-/*
- * 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.
- */
-
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.PreDestroy;
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.logging.Log;
-import org.apache.taverna.server.usagerecord.JobUsageRecord;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.utils.Contextualizer;
-import org.taverna.server.master.utils.JDOSupport;
-
-/**
- * A simple state-aware writer of usage records. It just appends them, one by
- * one, to the file whose name is stored in the state.
- * 
- * @author Donal Fellows
- */
-public class UsageRecordRecorder extends JDOSupport<UsageRecord> {
-	private Log log = getLog("Taverna.Server.Webapp");
-	public UsageRecordRecorder() {
-		super(UsageRecord.class);
-	}
-
-	private String logFile = null;
-	private boolean disableDB = false;
-	private ManagementModel state;
-	private Contextualizer contextualizer;
-	private String logDestination;
-	private PrintWriter writer;
-	private Object lock = new Object();
-	private UsageRecordRecorder self;
-
-	/**
-	 * @param state
-	 *            the state to set
-	 */
-	@Required
-	public void setState(ManagementModel state) {
-		this.state = state;
-	}
-
-	@Required
-	public void setSelf(UsageRecordRecorder self) {
-		this.self = self;
-	}
-
-	public void setLogFile(String logFile) {
-		this.logFile = (logFile == null || logFile.equals("none")) ? null : logFile;
-	}
-
-	public void setDisableDB(String disable) {
-		disableDB = "yes".equalsIgnoreCase(disable);
-	}
-
-	/**
-	 * @param contextualizer
-	 *            the system's contextualizer, used to allow making the UR dump
-	 *            file be placed relative to the webapp.
-	 */
-	@Required
-	public void setContextualizer(Contextualizer contextualizer) {
-		this.contextualizer = contextualizer;
-	}
-
-	/**
-	 * Accept a usage record for recording.
-	 * 
-	 * @param usageRecord
-	 *            The serialized usage record to record.
-	 */
-	public void storeUsageRecord(String usageRecord) {
-		String logfile = state.getUsageRecordLogFile();
-		if (logfile == null)
-			logfile = this.logFile;
-		if (logfile != null) {
-			logfile = contextualizer.contextualize(logfile);
-			synchronized (lock) {
-				if (!logfile.equals(logDestination)) {
-					if (writer != null) {
-						writer.close();
-						writer = null;
-					}
-					try {
-						writer = new PrintWriter(new FileWriter(logfile));
-						logDestination = logfile;
-					} catch (IOException e) {
-						log.warn("failed to open usage record log file", e);
-					}
-				}
-				if (writer != null) {
-					writer.println(usageRecord);
-					writer.flush();
-				}
-			}
-		}
-
-		if (!disableDB)
-			saveURtoDB(usageRecord);
-	}
-
-	/**
-	 * How to save a usage record to the database.
-	 * 
-	 * @param usageRecord
-	 *            The serialized usage record to save.
-	 */
-	protected void saveURtoDB(String usageRecord) {
-		UsageRecord ur;
-		try {
-			ur = new UsageRecord(usageRecord);
-		} catch (JAXBException e) {
-			log.warn("failed to deserialize usage record", e);
-			return;
-		}
-
-		try {
-			self.saveURtoDB(ur);
-		} catch (RuntimeException e) {
-			log.warn("failed to save UR to database", e);
-		}
-	}
-
-	@WithinSingleTransaction
-	public void saveURtoDB(UsageRecord ur) {
-		persist(ur);
-	}
-
-	@WithinSingleTransaction
-	public List<JobUsageRecord> getUsageRecords() {
-		List<String> urs = allByDate();
-		List<JobUsageRecord> result = new ArrayList<>();
-		for (String ur : urs)
-			try {
-				result.add(JobUsageRecord.unmarshal(ur));
-			} catch (JAXBException e) {
-				log.warn("failed to unmarshal UR", e);
-			}
-		return result;
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> allByDate() {
-		return (List<String>) namedQuery("allByDate").execute();
-	}
-
-	@PreDestroy
-	public void close() {
-		if (writer != null)
-			writer.close();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java
deleted file mode 100644
index a7fe733..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- */
-/**
- * Resource usage recording mechanism.
- */
-package org.taverna.server.master.usage;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java
deleted file mode 100644
index 4452935..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static java.lang.String.format;
-import static java.lang.System.nanoTime;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import org.apache.commons.logging.Log;
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.master.common.version.Version;
-
-/**
- * This class is responsible for timing all invocations of publicly-exposed
- * methods of the webapp. It's connected to the webapp through an AspectJ-style
- * pointcut that targets a custom annotation.
- * 
- * @author Donal Fellows
- */
-@Aspect
-@ManagedResource(objectName = JMX_ROOT + "PerformanceMonitor", description = "The performance monitor for Taverna Server "
-		+ Version.JAVA
-		+ ". Writes to application log using the category 'Taverna.Server.Performance'.")
-public class CallTimeLogger {
-	private long threshold = 4000000;
-	private Log log = getLog("Taverna.Server.Performance");
-
-	@ManagedAttribute(description = "Threshold beneath which monitored call times are not logged. In nanoseconds.")
-	public long getThreshold() {
-		return threshold;
-	}
-
-	@ManagedAttribute(description = "Threshold beneath which monitored call times are not logged. In nanoseconds.")
-	public void setThreshold(long threshold) {
-		this.threshold = threshold;
-	}
-
-	/**
-	 * The timer for this aspect. The wrapped invocation will be timed, and a
-	 * log message written if the configured threshold is exceeded.
-	 * 
-	 * @param call
-	 *            The call being wrapped.
-	 * @return The result of the call.
-	 * @throws Throwable
-	 *             If anything goes wrong with the wrapped call.
-	 * @see System#nanoTime()
-	 */
-	@Around("@annotation(org.taverna.server.master.utils.CallTimeLogger.PerfLogged)")
-	public Object time(ProceedingJoinPoint call) throws Throwable {
-		long fore = nanoTime();
-		try {
-			return call.proceed();
-		} finally {
-			long aft = nanoTime();
-			long elapsed = aft - fore;
-			if (elapsed > threshold)
-				log.info(format("call to %s took %.3fms", call.toShortString(),
-						elapsed / 1000000.0));
-		}
-	}
-
-	/**
-	 * Mark methods that should be counted by the invocation counter.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@Retention(RUNTIME)
-	@Documented
-	@Target(METHOD)
-	public static @interface PerfLogged {
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java
deleted file mode 100644
index d8ad78d..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * 
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static java.lang.String.format;
-import static java.lang.System.nanoTime;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.logging.Log;
-
-/**
- * Logs the time it takes to service HTTP calls into Taverna Server.
- * <p>
- * This class is currently not used.
- * 
- * @author Donal Fellows
- */
-public class CallTimingFilter implements Filter {
-	private Log log;
-	private String name;
-
-	@Override
-	public void init(FilterConfig filterConfig) throws ServletException {
-		log = getLog("Taverna.Server.Performance");
-		name = filterConfig.getInitParameter("name");
-	}
-
-	@Override
-	public void doFilter(ServletRequest request, ServletResponse response,
-			FilterChain chain) throws IOException, ServletException {
-		if (request instanceof HttpServletRequest)
-			doFilter((HttpServletRequest) request,
-					(HttpServletResponse) response, chain);
-		else
-			chain.doFilter(request, response);
-	}
-
-	public void doFilter(HttpServletRequest request,
-			HttpServletResponse response, FilterChain chain)
-			throws IOException, ServletException {
-		long start = nanoTime();
-		chain.doFilter(request, response);
-		long elapsedTime = nanoTime() - start;
-		log.info(format("%s call to %s %s took %.3fms", name,
-				request.getMethod(), request.getRequestURI(),
-				elapsedTime / 1000000.0));
-	}
-
-	@Override
-	public void destroy() {
-		log = null;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java
deleted file mode 100644
index 1387e05..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Properties;
-
-import javax.annotation.PostConstruct;
-
-import org.taverna.server.master.common.Capability;
-
-/**
- * Utility for listing the capabilities supported by this Taverna Server
- * installation.
- * 
- * @author Donal Fellows
- */
-public class CapabilityLister {
-	public static final String CAPABILITY_RESOURCE_FILE = "/capabilities.properties";
-	private Properties properties = new Properties();
-
-	@PostConstruct
-	void loadCapabilities() throws IOException {
-		try (InputStream is = getClass().getResourceAsStream(
-				CAPABILITY_RESOURCE_FILE)) {
-			if (is != null)
-				properties.load(is);
-		}
-	}
-
-	public List<Capability> getCapabilities() {
-		List<Capability> caps = new ArrayList<>();
-		for (Entry<Object, Object> entry : properties.entrySet()) {
-			Capability c = new Capability();
-			c.capability = URI.create(entry.getKey().toString());
-			c.version = entry.getValue().toString();
-			caps.add(c);
-		}
-		return caps;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java
deleted file mode 100644
index 76ef017..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.unmodifiableList;
-
-import java.io.IOException;
-import java.net.URI;
-import java.security.GeneralSecurityException;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-import javax.xml.ws.Holder;
-
-/**
- * Obtains the certificate chain for an arbitrary SSL service. Maintains a
- * cache.
- * 
- * @author Donal Fellows
- */
-public class CertificateChainFetcher {
-	public String getProtocol() {
-		return protocol;
-	}
-
-	public void setProtocol(String protocol) {
-		this.protocol = protocol;
-	}
-
-	public String getKeystoreType() {
-		return keystoreType;
-	}
-
-	public void setKeystoreType(String keystoreType) {
-		this.keystoreType = keystoreType;
-	}
-
-	public String getAlgorithm() {
-		return algorithm;
-	}
-
-	public void setAlgorithm(String algorithm) {
-		this.algorithm = algorithm;
-	}
-
-	public int getTimeout() {
-		return timeout;
-	}
-
-	public void setTimeout(int timeout) {
-		this.timeout = timeout;
-	}
-
-	public void setSecure(boolean secure) {
-		this.secure = secure;
-	}
-
-	private boolean secure = true;
-	private String protocol = "TLS";
-	private String keystoreType = KeyStore.getDefaultType();
-	private String algorithm = TrustManagerFactory.getDefaultAlgorithm();
-	private int timeout = 10000;
-
-	/**
-	 * Get the certificate chain for a service.
-	 * 
-	 * @param host
-	 *            The host (name or IP address) to contact the service on.
-	 * @param port
-	 *            The port to contact the service on.
-	 * @return The certificate chain, or <tt>null</tt> if no credentials are
-	 *         available.
-	 * @throws NoSuchAlgorithmException
-	 *             If the trust manager cannot be set up because of algorithm
-	 *             problems.
-	 * @throws KeyStoreException
-	 *             If the trust manager cannot be set up because of problems
-	 *             with the keystore type.
-	 * @throws CertificateException
-	 *             If a bad certificate is present in the default keystore;
-	 *             <i>should be impossible</i>.
-	 * @throws IOException
-	 *             If problems happen when trying to contact the service.
-	 * @throws KeyManagementException
-	 *             If the SSL context can't have its special context manager
-	 *             installed.
-	 */
-	private X509Certificate[] getCertificateChainForService(String host,
-			int port) throws NoSuchAlgorithmException, KeyStoreException,
-			CertificateException, IOException, KeyManagementException {
-		KeyStore ks = KeyStore.getInstance(keystoreType);
-		SSLContext context = SSLContext.getInstance(protocol);
-		TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
-		ks.load(null, null);
-		tmf.init(ks);
-		final Holder<X509Certificate[]> chain = new Holder<>();
-		final X509TrustManager defaultTrustManager = (X509TrustManager) tmf
-				.getTrustManagers()[0];
-		context.init(null, new TrustManager[] { new X509TrustManager() {
-			@Override
-			public void checkClientTrusted(X509Certificate[] clientChain,
-					String authType) throws CertificateException {
-				throw new UnsupportedOperationException();
-			}
-
-			@Override
-			public void checkServerTrusted(X509Certificate[] serverChain,
-					String authType) throws CertificateException {
-				chain.value = serverChain;
-				defaultTrustManager.checkServerTrusted(serverChain, authType);
-			}
-
-			@Override
-			public X509Certificate[] getAcceptedIssuers() {
-				throw new UnsupportedOperationException();
-			}
-		} }, null);
-		SSLSocketFactory factory = context.getSocketFactory();
-		try (SSLSocket socket = (SSLSocket) factory.createSocket(host, port)) {
-			socket.setSoTimeout(timeout);
-			socket.startHandshake();
-		} catch (SSLException e) {
-			// Ignore
-		}
-		return chain.value;
-	}
-
-	private Map<URI, List<X509Certificate>> cache = new HashMap<>();
-
-	/**
-	 * Gets the certificate chain for a service identified by URI.
-	 * 
-	 * @param uri
-	 *            The URI of the (secure) service to identify.
-	 * @return The certificate chain. Will be <tt>null</tt> if the service is
-	 *         not secure.
-	 * @throws IOException
-	 *             If the service is unreachable or other connection problems
-	 *             occur.
-	 * @throws GeneralSecurityException
-	 *             If any of a number of security-related problems occur, such
-	 *             as an inability to match detailed security protocols.
-	 */
-	public List<X509Certificate> getTrustsForURI(URI uri) throws IOException,
-			GeneralSecurityException {
-		if (!secure)
-			return null;
-		synchronized (this) {
-			if (!cache.containsKey(uri)) {
-				int port = uri.getPort();
-				if (port == -1)
-					switch (uri.getScheme()) {
-					case "http":
-						port = 80;
-						break;
-					case "https":
-						port = 443;
-						break;
-					default:
-						return null;
-					}
-				X509Certificate[] chain = getCertificateChainForService(
-						uri.getHost(), port);
-				if (chain != null)
-					cache.put(uri, unmodifiableList(asList(chain)));
-				else
-					cache.put(uri, null);
-			}
-			return cache.get(uri);
-		}
-	}
-
-	/**
-	 * Flushes the cache.
-	 */
-	public void flushCache() {
-		synchronized (this) {
-			cache.clear();
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java
deleted file mode 100644
index e0ee4d1..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import javax.servlet.ServletContext;
-import javax.ws.rs.core.UriInfo;
-
-import org.springframework.web.context.ServletContextAware;
-import org.taverna.server.master.common.version.Version;
-
-/**
- * Convert a string (URL, etc) to a version that is contextualized to the
- * web-application.
- * 
- * @author Donal Fellows
- */
-public class Contextualizer implements ServletContextAware {
-	static final String ROOT_PLACEHOLDER = "%{WEBAPPROOT}";
-	static final String VERSION_PLACEHOLDER = "%{VERSION}";
-	static final String BASE_PLACEHOLDER = "%{BASEURL}";
-
-	/**
-	 * Apply the contextualization operation. This consists of replacing the
-	 * string <tt>{@value #ROOT_PLACEHOLDER}</tt> with the real root of the webapp.
-	 * 
-	 * @param input
-	 *            the string to contextualize
-	 * @return the contextualized string
-	 */
-	public String contextualize(String input) {
-		// Hack to work around bizarre CXF bug
-		String path = context.getRealPath("/").replace("%2D", "-");
-		return input.replace(ROOT_PLACEHOLDER, path).replace(
-				VERSION_PLACEHOLDER, Version.JAVA);
-	}
-
-	/**
-	 * Apply the contextualization operation. This consists of replacing the
-	 * string <tt>{@value #ROOT_PLACEHOLDER}</tt> with the real root of the
-	 * webapp.
-	 * 
-	 * @param ui
-	 *            Where to get information about the URL used to access the
-	 *            webapp.
-	 * @param input
-	 *            the string to contextualize
-	 * @return the contextualized string
-	 */
-	public String contextualize(UriInfo ui, String input) {
-		// Hack to work around bizarre CXF bug
-		String baseuri = ui.getBaseUri().toString().replace("%2D", "-");
-		if (baseuri.endsWith("/"))
-			baseuri = baseuri.substring(0, baseuri.length() - 1);
-		return contextualize(input).replace(BASE_PLACEHOLDER, baseuri);
-	}
-
-	private ServletContext context;
-
-	@Override
-	public void setServletContext(ServletContext servletContext) {
-		context = servletContext;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java
deleted file mode 100644
index e4be90b..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Utility class, used to make Derby less broken.
- * 
- * @see <a
- *      href="http://stackoverflow.com/questions/1004327/getting-rid-of-derby-log">
- *      Getting rid of derby.log </a>
- * @see <a
- *      href="http://stackoverflow.com/questions/3339736/set-system-property-with-spring-configuration-file">
- *      Set system property with Spring configuration file </a>
- */
-public class DerbyUtils {
-	/**
-	 * A writer that channels things on to the log.
-	 */
-	public static final Writer TO_LOG = new DBLog();
-	// Hack
-	public static final Writer DEV_NULL = TO_LOG;
-}
-
-class DBLog extends Writer {
-	private Log log = LogFactory.getLog("Taverna.Server.Database");
-	private StringBuilder sb = new StringBuilder();
-	private boolean closed = false;
-
-	@Override
-	public void write(char[] cbuf, int off, int len) throws IOException {
-		if (closed)
-			throw new EOFException();
-		if (!log.isInfoEnabled())
-			return;
-		sb.append(cbuf, off, len);
-		while (!closed) {
-			int idx = sb.indexOf("\n"), realIdx = idx;
-			if (idx < 0)
-				break;
-			char ch;
-			while (idx > 0 && ((ch = sb.charAt(idx - 1)) == '\r' || ch == ' ' || ch == '\t'))
-				idx--;
-			if (idx > 0)
-				log.info(sb.substring(0, idx));
-			sb.delete(0, realIdx + 1);
-		}
-	}
-
-	@Override
-	public void flush() throws IOException {
-		if (sb.length() > 0) {
-			log.info(sb.toString());
-			sb = new StringBuilder();
-		}
-	}
-
-	@Override
-	public void close() throws IOException {
-		flush();
-		closed = true;
-		sb = null;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java
deleted file mode 100644
index 3c39326..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import java.util.List;
-
-import javax.ws.rs.core.PathSegment;
-
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * Utility functions for getting entries from directories.
- * 
- * @author Donal Fellows
- */
-public class FilenameUtils {
-	private static final String TYPE_ERROR = "trying to take subdirectory of file";
-	private static final String NO_FILE = "no such directory entry";
-	private static final String NOT_A_FILE = "not a file";
-	private static final String NOT_A_DIR = "not a directory";
-
-	/**
-	 * Get a named directory entry from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param name
-	 *            The name of the directory entry to look up.
-	 * @return The directory entry whose name is equal to the last part of the
-	 *         path; an empty path will retrieve the working directory handle
-	 *         itself.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable.
-	 */
-	public DirectoryEntry getDirEntry(TavernaRun run, String name)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		Directory dir = run.getWorkingDirectory();
-		if (name == null || name.isEmpty())
-			return dir;
-		DirectoryEntry found = dir;
-		boolean mustBeLast = false;
-
-		// Must be nested loops; avoids problems with %-encoded "/" chars
-		for (String bit : name.split("/")) {
-			if (mustBeLast)
-				throw new FilesystemAccessException(TYPE_ERROR);
-			found = getEntryFromDir(bit, dir);
-			dir = null;
-			if (found instanceof Directory) {
-				dir = (Directory) found;
-				mustBeLast = false;
-			} else
-				mustBeLast = true;
-		}
-		return found;
-	}
-
-	/**
-	 * Get a named directory entry from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param d
-	 *            The path segments describing what to look up.
-	 * @return The directory entry whose name is equal to the last part of the
-	 *         path; an empty path will retrieve the working directory handle
-	 *         itself.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable.
-	 */
-	public DirectoryEntry getDirEntry(TavernaRun run, List<PathSegment> d)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		Directory dir = run.getWorkingDirectory();
-		if (d == null || d.isEmpty())
-			return dir;
-		DirectoryEntry found = dir;
-		boolean mustBeLast = false;
-
-		// Must be nested loops; avoids problems with %-encoded "/" chars
-		for (PathSegment segment : d)
-			for (String bit : segment.getPath().split("/")) {
-				if (mustBeLast)
-					throw new FilesystemAccessException(TYPE_ERROR);
-				found = getEntryFromDir(bit, dir);
-				dir = null;
-				if (found instanceof Directory) {
-					dir = (Directory) found;
-					mustBeLast = false;
-				} else
-					mustBeLast = true;
-			}
-		return found;
-	}
-
-	/**
-	 * Get a named directory entry from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param d
-	 *            The directory reference describing what to look up.
-	 * @return The directory entry whose name is equal to the last part of the
-	 *         path in the directory reference; an empty path will retrieve the
-	 *         working directory handle itself.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public DirectoryEntry getDirEntry(TavernaRun run, DirEntryReference d)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		Directory dir = run.getWorkingDirectory();
-		if (d == null || d.path == null || d.path.isEmpty())
-			return dir;
-		DirectoryEntry found = dir;
-		boolean mustBeLast = false;
-
-		for (String bit : d.path.split("/")) {
-			if (mustBeLast)
-				throw new FilesystemAccessException(TYPE_ERROR);
-			found = getEntryFromDir(bit, dir);
-			dir = null;
-			if (found instanceof Directory) {
-				dir = (Directory) found;
-				mustBeLast = false;
-			} else
-				mustBeLast = true;
-		}
-		return found;
-	}
-
-	/**
-	 * Get a named directory entry from a directory.
-	 * 
-	 * @param name
-	 *            The name of the entry; must be "<tt>/</tt>"-free.
-	 * @param dir
-	 *            The directory to look in.
-	 * @return The directory entry whose name is equal to the given name.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable.
-	 */
-	private DirectoryEntry getEntryFromDir(String name, Directory dir)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		if (dir == null)
-			throw new FilesystemAccessException(NO_FILE);
-		for (DirectoryEntry entry : dir.getContents())
-			if (entry.getName().equals(name))
-				return entry;
-		throw new NoDirectoryEntryException(NO_FILE);
-	}
-
-	/**
-	 * Get a named directory from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param d
-	 *            The directory reference describing what to look up.
-	 * @return The directory whose name is equal to the last part of the path in
-	 *         the directory reference; an empty path will retrieve the working
-	 *         directory handle itself.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable, or if the
-	 *             name doesn't refer to a directory.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public Directory getDirectory(TavernaRun run, DirEntryReference d)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		DirectoryEntry dirEntry = getDirEntry(run, d);
-		if (dirEntry instanceof Directory)
-			return (Directory) dirEntry;
-		throw new FilesystemAccessException(NOT_A_DIR);
-	}
-
-	/**
-	 * Get a named directory from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param name
-	 *            The name of the directory to look up.
-	 * @return The directory.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable, or if the
-	 *             name doesn't refer to a directory.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public Directory getDirectory(TavernaRun run, String name)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		DirectoryEntry dirEntry = getDirEntry(run, name);
-		if (dirEntry instanceof Directory)
-			return (Directory) dirEntry;
-		throw new FilesystemAccessException(NOT_A_DIR);
-	}
-
-	/**
-	 * Get a named file from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param d
-	 *            The directory reference describing what to look up.
-	 * @return The file whose name is equal to the last part of the path in the
-	 *         directory reference; an empty path will retrieve the working
-	 *         directory handle itself.
-	 * @throws FilesystemAccessException
-	 *             If the file isn't specified or isn't readable, or if the name
-	 *             doesn't refer to a file.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public File getFile(TavernaRun run, DirEntryReference d)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		DirectoryEntry dirEntry = getDirEntry(run, d);
-		if (dirEntry instanceof File)
-			return (File) dirEntry;
-		throw new FilesystemAccessException(NOT_A_FILE);
-	}
-
-	/**
-	 * Get a named file from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param name
-	 *            The name of the file to look up.
-	 * @return The file whose name is equal to the last part of the path in the
-	 *         directory reference; an empty path will retrieve the working
-	 *         directory handle itself.
-	 * @throws FilesystemAccessException
-	 *             If the file isn't specified or isn't readable, or if the name
-	 *             doesn't refer to a file.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public File getFile(TavernaRun run, String name)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		DirectoryEntry dirEntry = getDirEntry(run, name);
-		if (dirEntry instanceof File)
-			return (File) dirEntry;
-		throw new FilesystemAccessException(NOT_A_FILE);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
deleted file mode 100644
index 7f5f92a..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import org.apache.cxf.jaxrs.provider.ProviderFactory;
-import org.apache.cxf.message.Message;
-import org.apache.cxf.phase.AbstractPhaseInterceptor;
-import org.apache.cxf.phase.Phase;
-
-public class FlushThreadLocalCacheInterceptor extends
-		AbstractPhaseInterceptor<Message> {
-	public FlushThreadLocalCacheInterceptor() {
-		super(Phase.USER_LOGICAL_ENDING);
-	}
-
-	@Override
-	public void handleMessage(Message message) {
-		ProviderFactory.getInstance(message).clearThreadLocalProxies();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java
deleted file mode 100644
index 0600857..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-
-/**
- * This class is responsible for counting all invocations of publicly-exposed
- * methods of the webapp. It's connected to the webapp primarily through an
- * AspectJ-style pointcut.
- * 
- * @author Donal Fellows
- */
-@Aspect
-public class InvocationCounter {
-	private int count;
-
-	@Before("@annotation(org.taverna.server.master.utils.InvocationCounter.CallCounted)")
-	public synchronized void count() {
-		count++;
-	}
-
-	public synchronized int getCount() {
-		return count;
-	}
-
-	/**
-	 * Mark methods that should be counted by the invocation counter.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@Retention(RUNTIME)
-	@Documented
-	@Target(METHOD)
-	public static @interface CallCounted {
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java
deleted file mode 100644
index 7f248ff..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static java.lang.Integer.MAX_VALUE;
-import static javax.crypto.Cipher.getMaxAllowedKeyLength;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.security.GeneralSecurityException;
-import java.security.NoSuchAlgorithmException;
-
-import javax.annotation.PostConstruct;
-
-import org.apache.commons.logging.Log;
-
-/**
- * Trivial bean that checks for whether the JCE policy files that allow
- * unlimited strength security are present, and warns in the log if not.
- * 
- * @author Donal Fellows
- */
-public class JCECheck {
-	/**
-	 * Write a message to the log that says whether an unlimited strength
-	 * {@linkplain #Cipher cipher} is present. This is the official proxy for
-	 * whether the unlimited strength JCE policy files have been installed; if
-	 * absent, the message is logged as a warning, otherwise it is just
-	 * informational.
-	 */
-	@PostConstruct
-	public void checkForUnlimitedJCE() {
-		Log log = getLog("Taverna.Server.Utils");
-
-		try {
-			if (getMaxAllowedKeyLength("AES") < MAX_VALUE)
-				log.warn("maximum key length very short; unlimited "
-						+ "strength JCE policy files maybe missing");
-			else
-				log.info("unlimited strength JCE policy in place");
-		} catch (GeneralSecurityException e) {
-			log.warn("problem computing key length limits!", e);
-		}
-	}
-
-	/**
-	 * @return Whether the unlimited strength JCE policy files are present (or
-	 *         rather whether an unlimited strength {@linkplain #Cipher cipher}
-	 *         is permitted).
-	 */
-	public boolean isUnlimitedStrength() {
-		try {
-			return getMaxAllowedKeyLength("AES") == MAX_VALUE;
-		} catch (NoSuchAlgorithmException e) {
-			return false;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java
deleted file mode 100644
index 96f6a11..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import java.util.WeakHashMap;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.PreDestroy;
-import javax.jdo.JDOException;
-import javax.jdo.PersistenceManager;
-import javax.jdo.PersistenceManagerFactory;
-import javax.jdo.Query;
-import javax.jdo.Transaction;
-
-import org.apache.commons.logging.Log;
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.springframework.beans.factory.annotation.Required;
-
-/**
- * Simple support class that wraps up and provides access to the correct parts
- * of JDO.
- * 
- * @author Donal Fellows
- * 
- * @param &lt;T&gt; The context class that the subclass will be working with.
- */
-public abstract class JDOSupport<T> {
-	private Class<T> contextClass;
-	private PersistenceManagerBuilder pmb;
-
-	/**
-	 * Instantiate this class, supplying it a handle to the class that will be
-	 * used to provide context for queries and accesses.
-	 * 
-	 * @param contextClass
-	 *            Must match the type parameter to the class itself.
-	 */
-	protected JDOSupport(@Nonnull Class<T> contextClass) {
-		this.contextClass = contextClass;
-	}
-
-	/**
-	 * @param persistenceManagerBuilder
-	 *            The JDO engine to use for managing persistence.
-	 */
-	@Required
-	public void setPersistenceManagerBuilder(
-			PersistenceManagerBuilder persistenceManagerBuilder) {
-		pmb = persistenceManagerBuilder;
-	}
-
-	private PersistenceManager pm() {
-		if (isPersistent())
-			return pmb.getPersistenceManager();
-		return null;
-	}
-
-	/**
-	 * Has this class actually been configured with a persistence manager by
-	 * Spring?
-	 * 
-	 * @return Whether there is a persistence manager installed.
-	 */
-	protected boolean isPersistent() {
-		return pmb != null;
-	}
-
-	/**
-	 * Get an instance of a query in JDOQL.
-	 * 
-	 * @param filter
-	 *            The filter part of the query.
-	 * @return The query, which should be executed to retrieve the results.
-	 */
-	@Nonnull
-	protected Query<T> query(@Nonnull String filter) {
-		return pm().newQuery(contextClass, filter);
-	}
-
-	/**
-	 * Get an instance of a named query attached to the context class (as an
-	 * annotation). Note that the result is a <i>raw</i> {@link Query} because
-	 * not all queries return instances of the context class.
-	 * 
-	 * @param name
-	 *            The name of the query.
-	 * @return The query, which should be executed to retrieve the results.
-	 * @see javax.jdo.annotations.Query
-	 */
-	@Nonnull
-	@SuppressWarnings("rawtypes")
-	protected Query namedQuery(@Nonnull String name) {
-		return pm().newNamedQuery(contextClass, name);
-	}
-
-	/**
-	 * Make an instance of the context class persist in the database. It's
-	 * identity must not already exist.
-	 * 
-	 * @param value
-	 *            The instance to persist.
-	 * @return The persistence-coupled instance.
-	 */
-	@Nullable
-	protected T persist(@Nullable T value) {
-		if (value == null)
-			return null;
-		return pm().makePersistent(value);
-	}
-
-	/**
-	 * Make a non-persistent (i.e., will hold its value past the end of the
-	 * transaction) copy of a persistence-coupled instance of the context class.
-	 * 
-	 * @param value
-	 *            The value to decouple.
-	 * @return The non-persistent copy.
-	 */
-	@Nullable
-	protected T detach(@Nullable T value) {
-		if (value == null)
-			return null;
-		return pm().detachCopy(value);
-	}
-
-	/**
-	 * Look up an instance of the context class by its identity.
-	 * 
-	 * @param id
-	 *            The identity of the object.
-	 * @return The instance, which is persistence-coupled.
-	 */
-	@Nullable
-	protected T getById(Object id) {
-		try {
-			return pm().getObjectById(contextClass, id);
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	/**
-	 * Delete a persistence-coupled instance of the context class.
-	 * 
-	 * @param value
-	 *            The value to delete.
-	 */
-	protected void delete(@Nullable T value) {
-		if (value != null)
-			pm().deletePersistent(value);
-	}
-
-	/**
-	 * Manages integration of JDO transactions with Spring.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@Aspect
-	public static class TransactionAspect {
-		private Object lock = new Object();
-		private Log log = getLog("Taverna.Server.Utils");
-		private volatile int txid;
-
-		@Around(value = "@annotation(org.taverna.server.master.utils.JDOSupport.WithinSingleTransaction) && target(support)", argNames = "support")
-		Object applyTransaction(ProceedingJoinPoint pjp, JDOSupport<?> support)
-				throws Throwable {
-			synchronized (lock) {
-				PersistenceManager pm = support.pm();
-				int id = ++txid;
-				Transaction tx = (pm == null) ? null : pm.currentTransaction();
-				if (tx != null && tx.isActive())
-					tx = null;
-				if (tx != null) {
-					if (log.isDebugEnabled())
-						log.debug("starting transaction #" + id);
-					tx.begin();
-				}
-				try {
-					Object result = pjp.proceed();
-					if (tx != null) {
-						tx.commit();
-						if (log.isDebugEnabled())
-							log.debug("committed transaction #" + id);
-					}
-					tx = null;
-					return result;
-				} catch (Throwable t) {
-					try {
-						if (tx != null) {
-							tx.rollback();
-							if (log.isDebugEnabled())
-								log.debug("rolled back transaction #" + id);
-						}
-					} catch (JDOException e) {
-						log.warn("rollback failed unexpectedly", e);
-					}
-					throw t;
-				}
-			}
-		}
-	}
-
-	/**
-	 * Mark a method (of a subclass of {@link JDOSupport}) as having a
-	 * transaction wrapped around it. The transactions are managed correctly in
-	 * the multi-threaded case.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@Target(METHOD)
-	@Retention(RUNTIME)
-	@Documented
-	public @interface WithinSingleTransaction {
-	}
-
-	/**
-	 * Manages {@linkplain PersistenceManager persistence managers} in a way
-	 * that doesn't cause problems when the web application is unloaded.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public static class PersistenceManagerBuilder {
-		private PersistenceManagerFactory pmf;
-		private WeakHashMap<Thread, PersistenceManager> cache = new WeakHashMap<>();
-
-		/**
-		 * @param persistenceManagerFactory
-		 *            The JDO engine to use for managing persistence.
-		 */
-		@Required
-		public void setPersistenceManagerFactory(
-				PersistenceManagerFactory persistenceManagerFactory) {
-			pmf = persistenceManagerFactory;
-		}
-
-		@Nonnull
-		public PersistenceManager getPersistenceManager() {
-			if (cache == null)
-				return pmf.getPersistenceManager();
-			Thread t = Thread.currentThread();
-			PersistenceManager pm = cache.get(t);
-			if (pm == null && pmf != null) {
-				pm = pmf.getPersistenceManager();
-				cache.put(t, pm);
-			}
-			return pm;
-		}
-
-		@PreDestroy
-		void clearThreadCache() {
-			WeakHashMap<Thread, PersistenceManager> cache = this.cache;
-			this.cache = null;
-			for (PersistenceManager pm : cache.values())
-				if (pm != null)
-					pm.close();
-			cache.clear();
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java
deleted file mode 100644
index 8bd0506..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import static java.lang.System.currentTimeMillis;
-import static java.lang.Thread.sleep;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.sql.DatabaseMetaData;
-import java.util.Properties;
-
-import org.apache.commons.logging.Log;
-import org.datanucleus.store.rdbms.adapter.DerbyAdapter;
-import org.datanucleus.store.rdbms.identifier.IdentifierFactory;
-import org.datanucleus.store.rdbms.key.CandidateKey;
-import org.datanucleus.store.rdbms.key.ForeignKey;
-import org.datanucleus.store.rdbms.key.Index;
-import org.datanucleus.store.rdbms.key.PrimaryKey;
-import org.datanucleus.store.rdbms.sql.SQLTable;
-import org.datanucleus.store.rdbms.table.Column;
-import org.datanucleus.store.rdbms.table.Table;
-import org.datanucleus.store.rdbms.table.TableImpl;
-import org.datanucleus.store.rdbms.table.ViewImpl;
-
-/**
- * Evil hack to allow logging of the DDL spat out to Derby.
- * 
- * @author Donal Fellows
- */
-public class LoggingDerbyAdapter extends DerbyAdapter {
-	Log log = getLog("Taverna.Server.SQL");
-
-	private StringBuilder ddl = new StringBuilder();
-	private volatile long timeout;
-	private Thread timer;
-
-	private synchronized void logDDL() {
-		if (ddl.length() > 0) {
-			log.info("Data definition language:\n" + ddl);
-			ddl.setLength(0);
-		}
-		timer = null;
-	}
-
-	private synchronized void doLog(String item) {
-		ddl.append(item);
-		if (!item.endsWith("\n"))
-			ddl.append('\n');
-		timeout = currentTimeMillis() + 5000;
-		if (timer == null)
-			timer = new OneShotThread("DDL logger timeout", new Runnable() {
-				@Override
-				public void run() {
-					try {
-						while (timeout > currentTimeMillis())
-							sleep(1000);
-					} catch (InterruptedException e) {
-						// Ignore
-					}
-					logDDL();
-				}
-			});
-	}
-
-	/**
-	 * Creates an Apache Derby adapter based on the given metadata which logs
-	 * the DDL it creates.
-	 */
-	public LoggingDerbyAdapter(DatabaseMetaData metadata) {
-		super(metadata);
-	}
-
-	@Override
-	public String getCreateTableStatement(TableImpl table, Column[] columns,
-			Properties props, IdentifierFactory factory) {
-		String statement = super.getCreateTableStatement(table, columns, props,
-				factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getCreateIndexStatement(Index index, IdentifierFactory factory) {
-		String statement = super.getCreateIndexStatement(index, factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getAddCandidateKeyStatement(CandidateKey ck,
-			IdentifierFactory factory) {
-		String statement = super.getAddCandidateKeyStatement(ck, factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getAddPrimaryKeyStatement(PrimaryKey pk,
-			IdentifierFactory factory) {
-		String statement = super.getAddPrimaryKeyStatement(pk, factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getAddColumnStatement(Table table, Column col) {
-		String statement = super.getAddColumnStatement(table, col);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getAddForeignKeyStatement(ForeignKey fk,
-			IdentifierFactory factory) {
-		String statement = super.getAddForeignKeyStatement(fk, factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getDeleteTableStatement(SQLTable tbl) {
-		String statement = super.getDeleteTableStatement(tbl);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getDropTableStatement(Table table) {
-		String statement = super.getDropTableStatement(table);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getDropViewStatement(ViewImpl view) {
-		String statement = super.getDropViewStatement(view);
-		doLog(statement);
-		return statement;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java
deleted file mode 100644
index 32cca5a..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-public class OneShotThread extends Thread {
-	public OneShotThread(String name, Runnable target) {
-		super(target, name);
-		setContextClassLoader(null);
-		setDaemon(true);
-		start();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java
deleted file mode 100644
index d69612e..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.core.Response;
-
-/**
- * Utilities that make it easier to write REST services.
- * 
- * @author Donal Fellows
- */
-public class RestUtils {
-	/**
-	 * Generate a response to an HTTP OPTIONS request.
-	 * 
-	 * @param methods
-	 *            The state-changing methods supported, if any.
-	 * @return the required response
-	 * @see OPTIONS
-	 */
-	public static Response opt(String... methods) {
-		StringBuilder sb = new StringBuilder("GET,");
-		for (String m : methods)
-			sb.append(m).append(",");
-		sb.append("HEAD,OPTIONS");
-		return Response.ok().header("Allow", sb.toString()).entity("").build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java
deleted file mode 100644
index 333febe..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import org.aspectj.lang.annotation.AfterThrowing;
-import org.aspectj.lang.annotation.Aspect;
-import org.taverna.server.master.exceptions.GeneralFailureException;
-
-/**
- * Aspect used to convert {@linkplain RuntimeException runtime exceptions} into
- * a form that can be nicely conveyed to the outside world as HTTP errors.
- * 
- * @author Donal Fellows
- */
-@Aspect
-public class RuntimeExceptionWrapper {
-	/**
-	 * Map an unexpected exception to one that can be correctly reported as a
-	 * problem.
-	 * 
-	 * @param exn
-	 *            The runtime exception being trapped.
-	 * @throws GeneralFailureException
-	 *             The known exception type that it is mapped to.
-	 */
-	@AfterThrowing(pointcut = "execution(* org.taverna.server.master.rest..*(..)) && !bean(*Provider.*)", throwing = "exn")
-	public void wrapRuntimeException(RuntimeException exn)
-			throws GeneralFailureException {
-		// Exclude security-related exceptions
-		if (exn.getClass().getName().startsWith("org.springframework.security."))
-			return;
-		throw new GeneralFailureException(exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java
deleted file mode 100644
index 25cf64f..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- */
-package org.taverna.server.master.utils;
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.security.Principal;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.userdetails.UserDetails;
-
-/**
- * A simple serializable principal that just records the name.
- * 
- * @author Donal Fellows
- */
-public class UsernamePrincipal implements Principal, Serializable {
-	private static final long serialVersionUID = 2703493248562435L;
-	public UsernamePrincipal(String username) {
-		this.name = username;
-	}
-
-	public UsernamePrincipal(Principal other) {
-		this.name = other.getName();
-	}
-
-	public UsernamePrincipal(Authentication auth) {
-		this(auth.getPrincipal());
-	}
-
-	public UsernamePrincipal(Object principal) {
-		if (principal instanceof Principal)
-			this.name = ((Principal) principal).getName();
-		else if (principal instanceof String)
-			this.name = (String) principal;
-		else if (principal instanceof UserDetails)
-			this.name = ((UserDetails) principal).getUsername();
-		else
-			this.name = principal.toString();
-	}
-
-	private String name;
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	@Override
-	public String toString() {
-		return "Principal<" + name + ">";
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if (o instanceof Principal) {
-			Principal p = (Principal) o;
-			return name.equals(p.getName());
-		}
-		return false;
-	}
-
-	@Override
-	public int hashCode() {
-		return name.hashCode();
-	}
-}



[06/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java
deleted file mode 100644
index 1c75d22..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.worker.RunConnection.toDBform;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.jdo.annotations.PersistenceAware;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.JDOSupport;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * This handles storing runs, interfacing with the underlying state engine as
- * necessary.
- * 
- * @author Donal Fellows
- */
-@PersistenceAware
-public class RunDatabaseDAO extends JDOSupport<RunConnection> {
-	public RunDatabaseDAO() {
-		super(RunConnection.class);
-	}
-
-	private Log log = LogFactory.getLog("Taverna.Server.Worker.RunDB");
-	private RunDatabase facade;
-
-	@Required
-	public void setFacade(RunDatabase facade) {
-		this.facade = facade;
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-
-	@SuppressWarnings("unchecked")
-	private List<String> names() {
-		if (log.isDebugEnabled())
-			log.debug("fetching all run names");
-		return (List<String>) namedQuery("names").execute();
-	}
-
-	/**
-	 * @return The number of workflow runs in the database.
-	 */
-	@WithinSingleTransaction
-	public int countRuns() {
-		if (log.isDebugEnabled())
-			log.debug("counting the number of runs");
-		return count();
-	}
-
-	private Integer count() {
-		return (Integer) namedQuery("count").execute();
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> timedout() {
-		return (List<String>) namedQuery("timedout").execute();
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> unterminated() {
-		return (List<String>) namedQuery("unterminated").execute();
-	}
-
-	@Nullable
-	private RunConnection pickRun(@Nonnull String name) {
-		if (log.isDebugEnabled())
-			log.debug("fetching the run called " + name);
-		try {
-			RunConnection rc = getById(name);
-			if (rc == null)
-				log.warn("no result for " + name);
-			return rc;
-		} catch (RuntimeException e) {
-			log.warn("problem in fetch", e);
-			throw e;
-		}
-	}
-
-	@Nullable
-	@WithinSingleTransaction
-	public String getSecurityToken(@Nonnull String name) {
-		RunConnection rc = getById(name);
-		if (rc == null)
-			return null;
-		return rc.getSecurityToken();
-	}
-
-	private void persist(@Nonnull RemoteRunDelegate rrd) throws IOException {
-		persist(toDBform(rrd));
-	}
-
-	@Nonnull
-	private List<RunConnection> allRuns() {
-		try {
-			List<RunConnection> rcs = new ArrayList<>();
-			List<String> names = names();
-			for (String id : names) {
-				try {
-					if (id != null)
-						rcs.add(pickRun(id));
-				} catch (RuntimeException e) {
-					continue;
-				}
-			}
-			return rcs;
-		} catch (RuntimeException e) {
-			log.warn("problem in fetch", e);
-			throw e;
-		}
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-
-	/**
-	 * Obtain a workflow run handle.
-	 * 
-	 * @param name
-	 *            The identifier of the run.
-	 * @return The run handle, or <tt>null</tt> if there is no such run.
-	 */
-	@Nullable
-	@WithinSingleTransaction
-	public TavernaRun get(String name) {
-		try {
-			RunConnection rc = pickRun(name);
-			return (rc == null) ? null : rc.fromDBform(facade);
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	/**
-	 * Get the runs that a user can read things from.
-	 * 
-	 * @param user
-	 *            Who is asking?
-	 * @param p
-	 *            The policy that determines what they can see.
-	 * @return A mapping from run IDs to run handles.
-	 */
-	@Nonnull
-	@WithinSingleTransaction
-	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
-		Map<String, TavernaRun> result = new HashMap<>();
-		for (String id : names())
-			try {
-				RemoteRunDelegate rrd = pickRun(id).fromDBform(facade);
-				if (p.permitAccess(user, rrd))
-					result.put(id, rrd);
-			} catch (Exception e) {
-				continue;
-			}
-		return result;
-	}
-
-	/**
-	 * @return A list of the IDs for all workflow runs.
-	 */
-	@Nonnull
-	@WithinSingleTransaction
-	public List<String> listRunNames() {
-		List<String> runNames = new ArrayList<>();
-		for (RunConnection rc : allRuns())
-			if (rc.getId() != null)
-				runNames.add(rc.getId());
-		return runNames;
-	}
-
-	/**
-	 * @return An arbitrary, representative workflow run.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	@Nullable
-	@WithinSingleTransaction
-	public RemoteRunDelegate pickArbitraryRun() throws Exception {
-		for (RunConnection rc : allRuns()) {
-			if (rc.getId() == null)
-				continue;
-			return rc.fromDBform(facade);
-		}
-		return null;
-	}
-
-	/**
-	 * Make a workflow run persistent. Must only be called once per workflow
-	 * run.
-	 * 
-	 * @param rrd
-	 *            The workflow run to persist.
-	 * @throws IOException
-	 *             If anything goes wrong with serialisation of the run.
-	 */
-	@WithinSingleTransaction
-	public void persistRun(@Nonnull RemoteRunDelegate rrd) throws IOException {
-		persist(rrd);
-	}
-
-	/**
-	 * Stop a workflow run from being persistent.
-	 * 
-	 * @param name
-	 *            The ID of the run.
-	 * @return Whether a deletion happened.
-	 */
-	@WithinSingleTransaction
-	public boolean unpersistRun(String name) {
-		RunConnection rc = pickRun(name);
-		if (rc != null)
-			delete(rc);
-		return rc != null;
-	}
-
-	/**
-	 * Ensure that the given workflow run is synchronized with the database.
-	 * 
-	 * @param run
-	 *            The run to synchronise.
-	 * @throws IOException
-	 *             If serialization of anything fails.
-	 */
-	@WithinSingleTransaction
-	public void flushToDisk(@Nonnull RemoteRunDelegate run) throws IOException {
-		getById(run.id).makeChanges(run);
-	}
-
-	/**
-	 * Remove all workflow runs that have expired.
-	 * 
-	 * @return The ids of the deleted runs.
-	 */
-	@Nonnull
-	@PerfLogged
-	@WithinSingleTransaction
-	public List<String> doClean() {
-		if (log.isDebugEnabled())
-			log.debug("deleting runs that timed out before " + new Date());
-		List<String> toDelete = timedout();
-		if (log.isDebugEnabled())
-			log.debug("found " + toDelete.size() + " runs to delete");
-		for (String id : toDelete) {
-			RunConnection rc = getById(id);
-			try {
-				rc.fromDBform(facade).run.destroy();
-			} catch (Exception e) {
-				if (log.isDebugEnabled())
-					log.debug("failed to delete execution resource for " + id,
-							e);
-			}
-			delete(rc);
-		}
-		return toDelete;
-	}
-
-	/**
-	 * @return A list of workflow runs that are candidates for doing
-	 *         notification of termination.
-	 */
-	@Nonnull
-	@PerfLogged
-	@WithinSingleTransaction
-	public List<RemoteRunDelegate> getPotentiallyNotifiable() {
-		List<RemoteRunDelegate> toNotify = new ArrayList<>();
-		for (String id : unterminated())
-			try {
-				RunConnection rc = getById(id);
-				toNotify.add(rc.fromDBform(facade));
-			} catch (Exception e) {
-				log.warn("failed to fetch connection token"
-						+ "for notification of completion check", e);
-			}
-		return toNotify;
-	}
-
-	@PerfLogged
-	@WithinSingleTransaction
-	public void markFinished(@Nonnull Set<String> terminated) {
-		for (String id : terminated) {
-			RunConnection rc = getById(id);
-			if (rc == null)
-				continue;
-			try {
-				rc.fromDBform(facade).doneTransitionToFinished = true;
-				rc.setFinished(true);
-			} catch (Exception e) {
-				log.warn("failed to note termination", e);
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java
deleted file mode 100644
index 642a6d6..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java
+++ /dev/null
@@ -1,411 +0,0 @@
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static org.springframework.jmx.support.MetricType.COUNTER;
-import static org.springframework.jmx.support.MetricType.GAUGE;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.annotation.Order;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedMetric;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.localworker.LocalWorkerState;
-
-@ManagedResource(objectName = JMX_ROOT + "Factory", description = "The factory for runs.")
-public abstract class RunFactoryConfiguration implements ConfigurableRunFactory {
-	protected Log log = LogFactory.getLog("Taverna.Server.Worker");
-	protected LocalWorkerState state;
-	protected RunDBSupport runDB;
-	private int totalRuns = 0;
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	@Autowired(required = true)
-	@Order(0)
-	void setState(LocalWorkerState state) {
-		this.state = state;
-	}
-
-	@Autowired(required = true)
-	@Order(0)
-	void setRunDB(RunDBSupport runDB) {
-		this.runDB = runDB;
-	}
-
-	/**
-	 * Drop any current references to the registry of runs, and kill off that
-	 * process.
-	 */
-	protected abstract void reinitRegistry();
-
-	/**
-	 * Drop any current references to the run factory subprocess and kill it
-	 * off.
-	 */
-	protected abstract void reinitFactory();
-
-	/** Count the number of operating runs. */
-	protected abstract int operatingCount() throws Exception;
-
-	protected final synchronized void incrementRunCount() {
-		totalRuns++;
-	}
-
-	@Override
-	@ManagedAttribute(description = "Whether it is allowed to start a run executing.", currencyTimeLimit = 30)
-	public final boolean isAllowingRunsToStart() {
-		try {
-			return state.getOperatingLimit() > getOperatingCount();
-		} catch (Exception e) {
-			log.info("failed to get operating run count", e);
-			return false;
-		}
-	}
-
-	@Override
-	@ManagedAttribute(description = "The host holding the RMI registry to communicate via.")
-	public final String getRegistryHost() {
-		return state.getRegistryHost();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The host holding the RMI registry to communicate via.")
-	public final void setRegistryHost(String host) {
-		state.setRegistryHost(host);
-		reinitRegistry();
-		reinitFactory();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The port number of the RMI registry. Should not normally be set.")
-	public final int getRegistryPort() {
-		return state.getRegistryPort();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The port number of the RMI registry. Should not normally be set.")
-	public final void setRegistryPort(int port) {
-		state.setRegistryPort(port);
-		reinitRegistry();
-		reinitFactory();
-	}
-
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "What JAR do we use to start the RMI registry process?")
-	public final String getRmiRegistryJar() {
-		return state.getRegistryJar();
-	}
-
-	@Override
-	@ManagedAttribute(description = "What JAR do we use to start the RMI registry process?")
-	public final void setRmiRegistryJar(String rmiRegistryJar) {
-		state.setRegistryJar(rmiRegistryJar);
-		reinitRegistry();
-		reinitFactory();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The maximum number of simultaneous runs supported by the server.", currencyTimeLimit = 300)
-	public final int getMaxRuns() {
-		return state.getMaxRuns();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The maximum number of simultaneous runs supported by the server.", currencyTimeLimit = 300)
-	public final void setMaxRuns(int maxRuns) {
-		state.setMaxRuns(maxRuns);
-	}
-
-	/** @return How many minutes should a workflow live by default? */
-	@Override
-	@ManagedAttribute(description = "How many minutes should a workflow live by default?", currencyTimeLimit = 300)
-	public final int getDefaultLifetime() {
-		return state.getDefaultLifetime();
-	}
-
-	/**
-	 * Set how long a workflow should live by default.
-	 * 
-	 * @param defaultLifetime
-	 *            Default lifetime, in minutes.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many minutes should a workflow live by default?", currencyTimeLimit = 300)
-	public final void setDefaultLifetime(int defaultLifetime) {
-		state.setDefaultLifetime(defaultLifetime);
-	}
-
-	/**
-	 * @return How many milliseconds to wait between checks to see if a worker
-	 *         process has registered.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many milliseconds to wait between checks to see if a worker process has registered.", currencyTimeLimit = 300)
-	public final int getSleepTime() {
-		return state.getSleepMS();
-	}
-
-	/**
-	 * @param sleepTime
-	 *            How many milliseconds to wait between checks to see if a
-	 *            worker process has registered.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many milliseconds to wait between checks to see if a worker process has registered.", currencyTimeLimit = 300)
-	public final void setSleepTime(int sleepTime) {
-		state.setSleepMS(sleepTime);
-	}
-
-	/**
-	 * @return How many seconds to wait for a worker process to register itself.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many seconds to wait for a worker process to register itself.", currencyTimeLimit = 300)
-	public final int getWaitSeconds() {
-		return state.getWaitSeconds();
-	}
-
-	/**
-	 * @param seconds
-	 *            How many seconds to wait for a worker process to register
-	 *            itself.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many seconds to wait for a worker process to register itself.", currencyTimeLimit = 300)
-	public final void setWaitSeconds(int seconds) {
-		state.setWaitSeconds(seconds);
-	}
-
-	/** @return The script to run to start running a workflow. */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The script to run to start running a workflow.", currencyTimeLimit = 300)
-	public final String getExecuteWorkflowScript() {
-		return state.getExecuteWorkflowScript();
-	}
-
-	/**
-	 * @param executeWorkflowScript
-	 *            The script to run to start running a workflow.
-	 */
-	@Override
-	@ManagedAttribute(description = "The script to run to start running a workflow.", currencyTimeLimit = 300)
-	public final void setExecuteWorkflowScript(String executeWorkflowScript) {
-		state.setExecuteWorkflowScript(executeWorkflowScript);
-		reinitFactory();
-	}
-
-	/** @return The location of the JAR implementing the server worker processes. */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The location of the JAR implementing the server worker processes.")
-	public final String getServerWorkerJar() {
-		return state.getServerWorkerJar();
-	}
-
-	/**
-	 * @param serverWorkerJar
-	 *            The location of the JAR implementing the server worker
-	 *            processes.
-	 */
-	@Override
-	@ManagedAttribute(description = "The location of the JAR implementing the server worker processes.")
-	public final void setServerWorkerJar(String serverWorkerJar) {
-		state.setServerWorkerJar(serverWorkerJar);
-		reinitFactory();
-	}
-
-	/** @return The list of additional arguments used to make a worker process. */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The list of additional arguments used to make a worker process.", currencyTimeLimit = 300)
-	public final String[] getExtraArguments() {
-		return state.getExtraArgs();
-	}
-
-	/**
-	 * @param extraArguments
-	 *            The list of additional arguments used to make a worker
-	 *            process.
-	 */
-	@Override
-	@ManagedAttribute(description = "The list of additional arguments used to make a worker process.", currencyTimeLimit = 300)
-	public final void setExtraArguments(@Nonnull String[] extraArguments) {
-		state.setExtraArgs(extraArguments);
-		reinitFactory();
-	}
-
-	/** @return Which java executable to run. */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "Which java executable to run.", currencyTimeLimit = 300)
-	public final String getJavaBinary() {
-		return state.getJavaBinary();
-	}
-
-	/**
-	 * @param javaBinary
-	 *            Which java executable to run.
-	 */
-	@Override
-	@ManagedAttribute(description = "Which java executable to run.", currencyTimeLimit = 300)
-	public final void setJavaBinary(@Nonnull String javaBinary) {
-		state.setJavaBinary(javaBinary);
-		reinitFactory();
-	}
-
-	/**
-	 * @return A file containing a password to use when running a program as
-	 *         another user (e.g., with sudo).
-	 */
-	@Nullable
-	@Override
-	@ManagedAttribute(description = "A file containing a password to use when running a program as another user (e.g., with sudo).", currencyTimeLimit = 300)
-	public final String getPasswordFile() {
-		return state.getPasswordFile();
-	}
-
-	/**
-	 * @param passwordFile
-	 *            A file containing a password to use when running a program as
-	 *            another user (e.g., with sudo).
-	 */
-	@Override
-	@ManagedAttribute(description = "A file containing a password to use when running a program as another user (e.g., with sudo).", currencyTimeLimit = 300)
-	public final void setPasswordFile(@Nullable String passwordFile) {
-		state.setPasswordFile(passwordFile);
-		reinitFactory();
-	}
-
-	/**
-	 * @return The location of the JAR implementing the secure-fork process.
-	 */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The location of the JAR implementing the secure-fork process.", currencyTimeLimit = 300)
-	public final String getServerForkerJar() {
-		return state.getServerForkerJar();
-	}
-
-	/**
-	 * @param serverForkerJar
-	 *            The location of the JAR implementing the secure-fork process.
-	 */
-	@Override
-	@ManagedAttribute(description = "The location of the JAR implementing the secure-fork process.", currencyTimeLimit = 300)
-	public final void setServerForkerJar(String forkerJarFilename) {
-		state.setServerForkerJar(forkerJarFilename);
-		reinitFactory();
-	}
-
-	/**
-	 * @return How many times has a workflow run been spawned by this engine.
-	 *         Restarts reset this counter.
-	 */
-	@Override
-	@ManagedMetric(description = "How many times has a workflow run been spawned by this engine.", currencyTimeLimit = 10, metricType = COUNTER, category = "throughput")
-	public final synchronized int getTotalRuns() {
-		return totalRuns;
-	}
-
-	/**
-	 * @return How many checks were done for the worker process the last time a
-	 *         spawn was tried.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
-	public abstract int getLastStartupCheckCount();
-
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The names of the current runs.", currencyTimeLimit = 5)
-	public final String[] getCurrentRunNames() {
-		List<String> names = runDB.listRunNames();
-		return names.toArray(new String[names.size()]);
-	}
-
-	@Override
-	@ManagedAttribute(description = "What the factory subprocess's main RMI interface is registered as.", currencyTimeLimit = 60)
-	public abstract String getFactoryProcessName();
-
-	/**
-	 * @return What was the exit code from the last time the factory subprocess
-	 *         was killed?
-	 */
-	@Override
-	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
-	public abstract Integer getLastExitCode();
-
-	/**
-	 * @return The mapping of user names to RMI factory IDs.
-	 */
-	@Override
-	@ManagedAttribute(description = "The mapping of user names to RMI factory IDs.", currencyTimeLimit = 60)
-	public abstract String[] getFactoryProcessMapping();
-
-	@Override
-	@ManagedAttribute(description = "The maximum number of simultaneous operating runs supported by the server.", currencyTimeLimit = 300)
-	public final void setOperatingLimit(int operatingLimit) {
-		state.setOperatingLimit(operatingLimit);
-	}
-
-	@Override
-	@ManagedAttribute(description = "The maximum number of simultaneous operating runs supported by the server.", currencyTimeLimit = 300)
-	public final int getOperatingLimit() {
-		return state.getOperatingLimit();
-	}
-
-	/**
-	 * @return A count of the number of runs believed to actually be in the
-	 *         {@linkplain uk.org.taverna.server.master.common.Status#Operating
-	 *         operating} state.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	@Override
-	@ManagedMetric(description = "How many workflow runs are currently actually executing.", currencyTimeLimit = 10, metricType = GAUGE, category = "throughput")
-	public final int getOperatingCount() throws Exception {
-		return operatingCount();
-	}
-
-	@Override
-	@ManagedAttribute(description="Whether to tell a workflow to generate provenance bundles by default.")
-	public final void setGenerateProvenance(boolean genProv) {
-		state.setGenerateProvenance(genProv);
-	}
-
-	@Override
-	@ManagedAttribute(description="Whether to tell a workflow to generate provenance bundles by default.")
-	public final boolean getGenerateProvenance() {
-		return state.getGenerateProvenance();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java
deleted file mode 100644
index bb76f85..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static java.lang.String.format;
-import static java.util.Arrays.fill;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.defaults.Default.CERTIFICATE_FIELD_NAMES;
-import static org.taverna.server.master.defaults.Default.CERTIFICATE_TYPE;
-import static org.taverna.server.master.defaults.Default.CREDENTIAL_FILE_SIZE_LIMIT;
-import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.rmi.RemoteException;
-import java.security.GeneralSecurityException;
-import java.security.Key;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-import javax.security.auth.x500.X500Principal;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.UriBuilder;
-import javax.xml.ws.handler.MessageContext;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContext;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteSecurityContext;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Implementation of a security context.
- * 
- * @author Donal Fellows
- */
-public abstract class SecurityContextDelegate implements TavernaSecurityContext {
-	Log log = LogFactory.getLog("Taverna.Server.Worker");
-	private final UsernamePrincipal owner;
-	private final List<Credential> credentials = new ArrayList<>();
-	private final List<Trust> trusted = new ArrayList<>();
-	private final RemoteRunDelegate run;
-	private final Object lock = new Object();
-	final SecurityContextFactory factory;
-
-	private transient Keystore keystore;
-	private transient Map<URI, String> uriToAliasMap;
-
-	/**
-	 * Initialise the context delegate.
-	 * 
-	 * @param run
-	 *            What workflow run is this for?
-	 * @param owner
-	 *            Who owns the workflow run?
-	 * @param factory
-	 *            What class built this object?
-	 */
-	protected SecurityContextDelegate(RemoteRunDelegate run,
-			UsernamePrincipal owner, SecurityContextFactory factory) {
-		this.run = run;
-		this.owner = owner;
-		this.factory = factory;
-	}
-
-	@Override
-	public SecurityContextFactory getFactory() {
-		return factory;
-	}
-
-	@Override
-	public UsernamePrincipal getOwner() {
-		return owner;
-	}
-
-	@Override
-	public Credential[] getCredentials() {
-		synchronized (lock) {
-			return credentials.toArray(new Credential[credentials.size()]);
-		}
-	}
-
-	/**
-	 * Get the human-readable name of a principal.
-	 * 
-	 * @param principal
-	 *            The principal being decoded.
-	 * @return A name.
-	 */
-	protected final String getPrincipalName(X500Principal principal) {
-		return factory.x500Utils.getName(principal, CERTIFICATE_FIELD_NAMES);
-	}
-
-	/**
-	 * Cause the current state to be flushed to the database.
-	 */
-	protected final void flushToDB() {
-		factory.db.flushToDisk(run);
-	}
-
-	@Override
-	public void addCredential(Credential toAdd) {
-		synchronized (lock) {
-			int idx = credentials.indexOf(toAdd);
-			if (idx != -1)
-				credentials.set(idx, toAdd);
-			else
-				credentials.add(toAdd);
-			flushToDB();
-		}
-	}
-
-	@Override
-	public void deleteCredential(Credential toDelete) {
-		synchronized (lock) {
-			credentials.remove(toDelete);
-			flushToDB();
-		}
-	}
-
-	@Override
-	public Trust[] getTrusted() {
-		synchronized (lock) {
-			return trusted.toArray(new Trust[trusted.size()]);
-		}
-	}
-
-	@Override
-	public void addTrusted(Trust toAdd) {
-		synchronized (lock) {
-			int idx = trusted.indexOf(toAdd);
-			if (idx != -1)
-				trusted.set(idx, toAdd);
-			else
-				trusted.add(toAdd);
-			flushToDB();
-		}
-	}
-
-	@Override
-	public void deleteTrusted(Trust toDelete) {
-		synchronized (lock) {
-			trusted.remove(toDelete);
-			flushToDB();
-		}
-	}
-
-	@Override
-	public abstract void validateCredential(Credential c)
-			throws InvalidCredentialException;
-
-	@Override
-	public void validateTrusted(Trust t) throws InvalidCredentialException {
-		InputStream contentsAsStream;
-		if (t.certificateBytes != null && t.certificateBytes.length > 0) {
-			contentsAsStream = new ByteArrayInputStream(t.certificateBytes);
-			t.certificateFile = null;
-		} else if (t.certificateFile == null
-				|| t.certificateFile.trim().isEmpty())
-			throw new InvalidCredentialException(
-					"absent or empty certificateFile");
-		else {
-			contentsAsStream = contents(t.certificateFile);
-			t.certificateBytes = null;
-		}
-		t.serverName = null;
-		if (t.fileType == null || t.fileType.trim().isEmpty())
-			t.fileType = CERTIFICATE_TYPE;
-		t.fileType = t.fileType.trim();
-		try {
-			t.loadedCertificates = CertificateFactory.getInstance(t.fileType)
-					.generateCertificates(contentsAsStream);
-			t.serverName = new ArrayList<>(t.loadedCertificates.size());
-			for (Certificate c : t.loadedCertificates)
-				t.serverName.add(getPrincipalName(((X509Certificate) c)
-						.getSubjectX500Principal()));
-		} catch (CertificateException e) {
-			throw new InvalidCredentialException(e);
-		} catch (ClassCastException e) {
-			// Do nothing; truncates the list of server names
-		}
-	}
-
-	@Override
-	public void initializeSecurityFromContext(SecurityContext securityContext)
-			throws Exception {
-		// This is how to get the info from Spring Security
-		Authentication auth = securityContext.getAuthentication();
-		if (auth == null)
-			return;
-		auth.getPrincipal();
-		// do nothing else in this implementation
-	}
-
-	@Override
-	public void initializeSecurityFromSOAPContext(MessageContext context) {
-		// do nothing in this implementation
-	}
-
-	@Override
-	public void initializeSecurityFromRESTContext(HttpHeaders context) {
-		// do nothing in this implementation
-	}
-
-	private UriBuilder getUB() {
-		return factory.uriSource.getRunUriBuilder(run);
-	}
-
-	private RunDatabaseDAO getDAO() {
-		return ((RunDatabase) factory.db).dao;
-	}
-
-	@Nullable
-	private List<X509Certificate> getCerts(URI uri) throws IOException,
-			GeneralSecurityException {
-		return factory.certFetcher.getTrustsForURI(uri);
-	}
-
-	private void installLocalPasswordCredential(List<Credential> credentials,
-			List<Trust> trusts) throws InvalidCredentialException, IOException,
-			GeneralSecurityException {
-		Credential.Password pw = new Credential.Password();
-		pw.id = "run:self";
-		pw.username = PREFIX + run.id;
-		pw.password = getDAO().getSecurityToken(run.id);
-		UriBuilder ub = getUB().segment("").fragment(factory.httpRealm);
-		pw.serviceURI = ub.build();
-		validateCredential(pw);
-		log.info("issuing self-referential credential for " + pw.serviceURI);
-		credentials.add(pw);
-		List<X509Certificate> myCerts = getCerts(pw.serviceURI);
-		if (myCerts != null && myCerts.size() > 0) {
-			Trust t = new Trust();
-			t.loadedCertificates = getCerts(pw.serviceURI);
-			trusts.add(t);
-		}
-	}
-
-	/**
-	 * Builds and transfers a keystore with suitable credentials to the back-end
-	 * workflow execution engine.
-	 * 
-	 * @throws GeneralSecurityException
-	 *             If the manipulation of the keystore, keys or certificates
-	 *             fails.
-	 * @throws IOException
-	 *             If there are problems building the data (should not happen).
-	 * @throws RemoteException
-	 *             If the conveyancing fails.
-	 */
-	@Override
-	public final void conveySecurity() throws GeneralSecurityException,
-			IOException, ImplementationException {
-		RemoteSecurityContext rc = run.run.getSecurityContext();
-
-		List<Trust> trusted = new ArrayList<>(this.trusted);
-		this.trusted.clear();
-		List<Credential> credentials = new ArrayList<>(this.credentials);
-		this.credentials.clear();
-
-		try {
-			installLocalPasswordCredential(credentials, trusted);
-		} catch (Exception e) {
-			log.warn("failed to construct local credential: "
-					+ "interaction service will fail", e);
-		}
-
-		char[] password = null;
-		try {
-			password = generateNewPassword();
-
-			log.info("constructing merged keystore");
-			Truststore truststore = new Truststore(password);
-			Keystore keystore = new Keystore(password);
-			Map<URI, String> uriToAliasMap = new HashMap<>();
-			int trustedCount = 0, keyCount = 0;
-
-			synchronized (lock) {
-				try {
-					for (Trust t : trusted) {
-						if (t == null || t.loadedCertificates == null)
-							continue;
-						for (Certificate cert : t.loadedCertificates)
-							if (cert != null) {
-								truststore.addCertificate(cert);
-								trustedCount++;
-							}
-					}
-
-					this.uriToAliasMap = uriToAliasMap;
-					this.keystore = keystore;
-					for (Credential c : credentials) {
-						addCredentialToKeystore(c);
-						keyCount++;
-					}
-				} finally {
-					this.uriToAliasMap = null;
-					this.keystore = null;
-					credentials.clear();
-					trusted.clear();
-					flushToDB();
-				}
-			}
-
-			byte[] trustbytes = null, keybytes = null;
-			try {
-				trustbytes = truststore.serialize();
-				keybytes = keystore.serialize();
-
-				// Now we've built the security information, ship it off...
-
-				log.info("transfering merged truststore with " + trustedCount
-						+ " entries");
-				rc.setTruststore(trustbytes);
-
-				log.info("transfering merged keystore with " + keyCount
-						+ " entries");
-				rc.setKeystore(keybytes);
-			} finally {
-				if (trustbytes != null)
-					fill(trustbytes, (byte) 0);
-				if (keybytes != null)
-					fill(keybytes, (byte) 0);
-			}
-			rc.setPassword(password);
-
-			log.info("transferring serviceURL->alias map with "
-					+ uriToAliasMap.size() + " entries");
-			rc.setUriToAliasMap(uriToAliasMap);
-		} finally {
-			if (password != null)
-				fill(password, ' ');
-		}
-
-		synchronized (lock) {
-			conveyExtraSecuritySettings(rc);
-		}
-	}
-
-	/**
-	 * Hook that allows additional information to be conveyed to the remote run.
-	 * 
-	 * @param remoteSecurityContext
-	 *            The remote resource that information would be passed to.
-	 * @throws IOException
-	 *             If anything goes wrong with the communication.
-	 */
-	protected void conveyExtraSecuritySettings(
-			RemoteSecurityContext remoteSecurityContext) throws IOException {
-		// Does nothing by default; overrideable
-	}
-
-	/**
-	 * @return A new password with a reasonable level of randomness.
-	 */
-	protected final char[] generateNewPassword() {
-		return randomUUID().toString().toCharArray();
-	}
-
-	/**
-	 * Adds a credential to the current keystore.
-	 * 
-	 * @param alias
-	 *            The alias to create within the keystore.
-	 * @param c
-	 *            The key-pair.
-	 * @throws KeyStoreException
-	 */
-	protected final void addKeypairToKeystore(String alias, Credential c)
-			throws KeyStoreException {
-		if (c.loadedKey == null)
-			throw new KeyStoreException("critical: credential was not verified");
-		if (uriToAliasMap.containsKey(c.serviceURI))
-			log.warn("duplicate URI in alias mapping: " + c.serviceURI);
-		keystore.addKey(alias, c.loadedKey, c.loadedTrustChain);
-		uriToAliasMap.put(c.serviceURI, alias);
-	}
-
-	/**
-	 * Adds a credential to the current keystore.
-	 * 
-	 * @param c
-	 *            The credential to add.
-	 * @throws KeyStoreException
-	 */
-	public abstract void addCredentialToKeystore(Credential c)
-			throws KeyStoreException;
-
-	/**
-	 * Read a file up to {@value #FILE_SIZE_LIMIT}kB in size.
-	 * 
-	 * @param name
-	 *            The path name of the file, relative to the context run's
-	 *            working directory.
-	 * @return A stream of the file's contents.
-	 * @throws InvalidCredentialException
-	 *             If anything goes wrong.
-	 */
-	final InputStream contents(String name) throws InvalidCredentialException {
-		try {
-			File f = (File) factory.fileUtils.getDirEntry(run, name);
-			long size = f.getSize();
-			if (size > CREDENTIAL_FILE_SIZE_LIMIT * 1024)
-				throw new InvalidCredentialException(CREDENTIAL_FILE_SIZE_LIMIT
-						+ "kB limit hit");
-			return new ByteArrayInputStream(f.getContents(0, (int) size));
-		} catch (NoDirectoryEntryException | FilesystemAccessException e) {
-			throw new InvalidCredentialException(e);
-		} catch (ClassCastException e) {
-			throw new InvalidCredentialException("not a file", e);
-		}
-	}
-
-	@Override
-	public Set<String> getPermittedDestroyers() {
-		return run.getDestroyers();
-	}
-
-	@Override
-	public void setPermittedDestroyers(Set<String> destroyers) {
-		run.setDestroyers(destroyers);
-	}
-
-	@Override
-	public Set<String> getPermittedUpdaters() {
-		return run.getWriters();
-	}
-
-	@Override
-	public void setPermittedUpdaters(Set<String> updaters) {
-		run.setWriters(updaters);
-	}
-
-	@Override
-	public Set<String> getPermittedReaders() {
-		return run.getReaders();
-	}
-
-	@Override
-	public void setPermittedReaders(Set<String> readers) {
-		run.setReaders(readers);
-	}
-
-	/**
-	 * Reinstall the credentials and the trust extracted from serialization to
-	 * the database.
-	 * 
-	 * @param credentials
-	 *            The credentials to reinstall.
-	 * @param trust
-	 *            The trusted certificates to reinstall.
-	 */
-	void setCredentialsAndTrust(Credential[] credentials, Trust[] trust) {
-		synchronized (lock) {
-			this.credentials.clear();
-			if (credentials != null)
-				for (Credential c : credentials)
-					try {
-						validateCredential(c);
-						this.credentials.add(c);
-					} catch (InvalidCredentialException e) {
-						log.warn("failed to revalidate credential: " + c, e);
-					}
-			this.trusted.clear();
-			if (trust != null)
-				for (Trust t : trust)
-					try {
-						validateTrusted(t);
-						this.trusted.add(t);
-					} catch (InvalidCredentialException e) {
-						log.warn("failed to revalidate trust assertion: " + t,
-								e);
-					}
-		}
-	}
-
-	static class SecurityStore {
-		private KeyStore ks;
-		private char[] password;
-
-		SecurityStore(char[] password) throws GeneralSecurityException {
-			this.password = password.clone();
-			ks = KeyStore.getInstance("UBER", "BC");
-			try {
-				ks.load(null, this.password);
-			} catch (IOException e) {
-				throw new GeneralSecurityException(
-						"problem initializing blank truststore", e);
-			}
-		}
-
-		final synchronized void setCertificate(String alias, Certificate c)
-				throws KeyStoreException {
-			if (ks == null)
-				throw new IllegalStateException("store already written");
-			ks.setCertificateEntry(alias, c);
-		}
-
-		final synchronized void setKey(String alias, Key key, Certificate[] trustChain)
-				throws KeyStoreException {
-			if (ks == null)
-				throw new IllegalStateException("store already written");
-			ks.setKeyEntry(alias, key, password, trustChain);
-		}
-
-		final synchronized byte[] serialize(boolean logIt)
-				throws GeneralSecurityException {
-			if (ks == null)
-				throw new IllegalStateException("store already written");
-			try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
-				ks.store(stream, password);
-				if (logIt)
-					LogFactory.getLog("Taverna.Server.Worker").debug(
-							"serialized UBER/BC truststore (size: " + ks.size()
-									+ ") with password \""
-									+ new String(password) + "\"");
-				return stream.toByteArray();
-			} catch (IOException e) {
-				throw new GeneralSecurityException(
-						"problem serializing keystore", e);
-			} finally {
-				ks = null;
-				fill(password, ' ');
-			}
-		}
-
-		@Override
-		protected final void finalize() {
-			fill(password, ' ');
-			ks = null;
-		}
-	}
-
-	/**
-	 * A trust store that can only be added to or serialized. Only trusted
-	 * certificates can be placed in it.
-	 * 
-	 * @author Donal Fellows
-	 */
-	class Truststore extends SecurityStore {
-		Truststore(char[] password) throws GeneralSecurityException {
-			super(password);
-		}
-
-		/**
-		 * Add a trusted certificate to the truststore. No certificates can be
-		 * added after the truststore is serialized.
-		 * 
-		 * @param cert
-		 *            The certificate (typically belonging to a root CA) to add.
-		 * @throws KeyStoreException
-		 *             If anything goes wrong.
-		 */
-		public void addCertificate(Certificate cert) throws KeyStoreException {
-			X509Certificate c = (X509Certificate) cert;
-			String alias = format("trustedcert#%s#%s#%s",
-					getPrincipalName(c.getSubjectX500Principal()),
-					getPrincipalName(c.getIssuerX500Principal()),
-					factory.x500Utils.getSerial(c));
-			setCertificate(alias, c);
-			if (log.isDebugEnabled() && factory.logSecurityDetails)
-				log.debug("added cert with alias \"" + alias + "\" of type "
-						+ c.getClass().getCanonicalName());
-		}
-
-		/**
-		 * Get the byte serialization of this truststore. This can only be
-		 * fetched exactly once.
-		 * 
-		 * @return The serialization.
-		 * @throws GeneralSecurityException
-		 *             If anything goes wrong.
-		 */
-		public byte[] serialize() throws GeneralSecurityException {
-			return serialize(log.isDebugEnabled() && factory.logSecurityDetails);
-		}
-	}
-
-	/**
-	 * A key store that can only be added to or serialized. Only keys can be
-	 * placed in it.
-	 * 
-	 * @author Donal Fellows
-	 */
-	class Keystore extends SecurityStore {
-		Keystore(char[] password) throws GeneralSecurityException {
-			super(password);
-		}
-
-		/**
-		 * Add a key to the keystore. No keys can be added after the keystore is
-		 * serialized.
-		 * 
-		 * @param alias
-		 *            The alias of the key.
-		 * @param key
-		 *            The secret/private key to add.
-		 * @param trustChain
-		 *            The trusted certificate chain of the key. Should be
-		 *            <tt>null</tt> for secret keys.
-		 * @throws KeyStoreException
-		 *             If anything goes wrong.
-		 */
-		public void addKey(String alias, Key key, Certificate[] trustChain)
-				throws KeyStoreException {
-			setKey(alias, key, trustChain);
-			if (log.isDebugEnabled() && factory.logSecurityDetails)
-				log.debug("added key with alias \"" + alias + "\" of type "
-						+ key.getClass().getCanonicalName());
-		}
-
-		/**
-		 * Get the byte serialization of this keystore. This can only be fetched
-		 * exactly once.
-		 * 
-		 * @return The serialization.
-		 * @throws GeneralSecurityException
-		 *             If anything goes wrong.
-		 */
-		public byte[] serialize() throws GeneralSecurityException {
-			return serialize(log.isDebugEnabled() && factory.logSecurityDetails);
-		}
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java
deleted file mode 100644
index ef29b55..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static java.lang.String.format;
-import static javax.xml.ws.handler.MessageContext.HTTP_REQUEST_HEADERS;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.Charset;
-import java.rmi.RemoteException;
-import java.security.Key;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.List;
-import java.util.Map;
-
-import javax.crypto.spec.SecretKeySpec;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.xml.ws.handler.MessageContext;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.taverna.server.localworker.remote.RemoteSecurityContext;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.utils.X500Utils;
-
-/**
- * Factoring out of the part of the security context handling that actually
- * deals with the different types of credentials.
- * 
- * @author Donal Fellows
- */
-class SecurityContextDelegateImpl extends SecurityContextDelegate {
-	private static final char USERNAME_PASSWORD_SEPARATOR = '\u0000';
-	private static final String USERNAME_PASSWORD_KEY_ALGORITHM = "DUMMY";
-	/** What passwords are encoded as. */
-	private static final Charset UTF8 = Charset.forName("UTF-8");
-
-	private X500Utils x500Utils;
-
-	/**
-	 * Initialise the context delegate.
-	 * 
-	 * @param run
-	 *            What workflow run is this for?
-	 * @param owner
-	 *            Who owns the workflow run?
-	 * @param factory
-	 *            What class built this object?
-	 */
-	protected SecurityContextDelegateImpl(RemoteRunDelegate run,
-			UsernamePrincipal owner, SecurityContextFactory factory) {
-		super(run, owner, factory);
-		this.x500Utils = factory.x500Utils;
-	}
-
-	@Override
-	public void validateCredential(Credential c)
-			throws InvalidCredentialException {
-		try {
-			if (c instanceof Credential.Password)
-				validatePasswordCredential((Credential.Password) c);
-			else if (c instanceof Credential.KeyPair)
-				validateKeyCredential((Credential.KeyPair) c);
-			else
-				throw new InvalidCredentialException("unknown credential type");
-		} catch (InvalidCredentialException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new InvalidCredentialException(e);
-		}
-	}
-
-	@Override
-	public void addCredentialToKeystore(Credential c) throws KeyStoreException {
-		try {
-			if (c instanceof Credential.Password)
-				addUserPassToKeystore((Credential.Password) c);
-			else if (c instanceof Credential.KeyPair)
-				addKeypairToKeystore((Credential.KeyPair) c);
-			else
-				throw new KeyStoreException("unknown credential type");
-		} catch (KeyStoreException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new KeyStoreException(e);
-		}
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	/**
-	 * Tests whether the given username+password credential descriptor is valid.
-	 * If it is invalid, an exception will be thrown describing what the problem
-	 * is. Validation mainly consists of listing what the username is.
-	 * 
-	 * @param passwordDescriptor
-	 *            The credential descriptor to validate.
-	 * @throws InvalidCredentialException
-	 *             If the username is empty. NB: the password may be empty!
-	 *             That's legal (if unwise).
-	 */
-	protected void validatePasswordCredential(
-			Credential.Password passwordDescriptor)
-			throws InvalidCredentialException {
-		if (passwordDescriptor.username == null
-				|| passwordDescriptor.username.trim().isEmpty())
-			throw new InvalidCredentialException("absent or empty username");
-		if (passwordDescriptor.serviceURI == null)
-			throw new InvalidCredentialException("absent service URI");
-		String keyToSave = passwordDescriptor.username
-				+ USERNAME_PASSWORD_SEPARATOR + passwordDescriptor.password;
-		passwordDescriptor.loadedKey = encodeKey(keyToSave);
-		passwordDescriptor.loadedTrustChain = null;
-	}
-
-	private static Key encodeKey(String key) {
-		return new SecretKeySpec(key.getBytes(UTF8),
-				USERNAME_PASSWORD_KEY_ALGORITHM);
-	}
-
-	/**
-	 * Adds a username/password credential pair to the current keystore.
-	 * 
-	 * @param userpassCredential
-	 *            The username and password.
-	 * @throws KeyStoreException
-	 */
-	protected void addUserPassToKeystore(Credential.Password userpassCredential)
-			throws KeyStoreException {
-		String alias = format("password#%s",
-				userpassCredential.serviceURI.toASCIIString());
-		addKeypairToKeystore(alias, userpassCredential);
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	/**
-	 * Tests whether the given key-pair credential descriptor is valid. If it is
-	 * invalid, an exception will be thrown describing what the problem is.
-	 * 
-	 * @param keypairDescriptor
-	 *            The descriptor to validate.
-	 * @throws InvalidCredentialException
-	 *             If the descriptor is invalid
-	 * @throws KeyStoreException
-	 *             If we don't understand the keystore type or the contents of
-	 *             the keystore
-	 * @throws NoSuchAlgorithmException
-	 *             If the keystore is of a known type but we can't comprehend
-	 *             its security
-	 * @throws CertificateException
-	 *             If the keystore does not include enough information about the
-	 *             trust chain of the keypair
-	 * @throws UnrecoverableKeyException
-	 *             If we can't get the key out of the keystore
-	 * @throws IOException
-	 *             If we can't read the keystore for prosaic reasons (e.g., file
-	 *             absent)
-	 */
-	protected void validateKeyCredential(Credential.KeyPair keypairDescriptor)
-			throws InvalidCredentialException, KeyStoreException,
-			NoSuchAlgorithmException, CertificateException, IOException,
-			UnrecoverableKeyException {
-		if (keypairDescriptor.credentialName == null
-				|| keypairDescriptor.credentialName.trim().isEmpty())
-			throw new InvalidCredentialException(
-					"absent or empty credentialName");
-
-		InputStream contentsAsStream;
-		if (keypairDescriptor.credentialBytes != null
-				&& keypairDescriptor.credentialBytes.length > 0) {
-			contentsAsStream = new ByteArrayInputStream(
-					keypairDescriptor.credentialBytes);
-			keypairDescriptor.credentialFile = null;
-		} else if (keypairDescriptor.credentialFile == null
-				|| keypairDescriptor.credentialFile.trim().isEmpty())
-			throw new InvalidCredentialException(
-					"absent or empty credentialFile");
-		else {
-			contentsAsStream = contents(keypairDescriptor.credentialFile);
-			keypairDescriptor.credentialBytes = new byte[0];
-		}
-		if (keypairDescriptor.fileType == null
-				|| keypairDescriptor.fileType.trim().isEmpty())
-			keypairDescriptor.fileType = KeyStore.getDefaultType();
-		keypairDescriptor.fileType = keypairDescriptor.fileType.trim();
-
-		KeyStore ks = KeyStore.getInstance(keypairDescriptor.fileType);
-		char[] password = keypairDescriptor.unlockPassword.toCharArray();
-		ks.load(contentsAsStream, password);
-
-		try {
-			keypairDescriptor.loadedKey = ks.getKey(
-					keypairDescriptor.credentialName, password);
-		} catch (UnrecoverableKeyException ignored) {
-			keypairDescriptor.loadedKey = ks.getKey(
-					keypairDescriptor.credentialName, new char[0]);
-		}
-		if (keypairDescriptor.loadedKey == null)
-			throw new InvalidCredentialException(
-					"no such credential in key store");
-		keypairDescriptor.loadedTrustChain = ks
-				.getCertificateChain(keypairDescriptor.credentialName);
-		if (keypairDescriptor.loadedTrustChain == null
-				|| keypairDescriptor.loadedTrustChain.length == 0)
-			throw new InvalidCredentialException(
-					"could not establish trust chain for credential");
-	}
-
-	/**
-	 * Adds a key-pair to the current keystore.
-	 * 
-	 * @param c
-	 *            The key-pair.
-	 * @throws KeyStoreException
-	 */
-	protected void addKeypairToKeystore(Credential.KeyPair c)
-			throws KeyStoreException {
-		X509Certificate subjectCert = (X509Certificate) c.loadedTrustChain[0];
-		String alias = format("keypair#%s#%s#%s",
-				getPrincipalName(subjectCert.getSubjectX500Principal()),
-				getPrincipalName(subjectCert.getIssuerX500Principal()),
-				x500Utils.getSerial(subjectCert));
-		addKeypairToKeystore(alias, c);
-	}
-}
-
-/**
- * Special subclass that adds support for HELIO project security tokens.
- * 
- * @author Donal Fellows
- */
-class HelioSecurityContextDelegateImpl extends SecurityContextDelegateImpl {
-	/**
-	 * Initialise the context delegate.
-	 * 
-	 * @param run
-	 *            What workflow run is this for?
-	 * @param owner
-	 *            Who owns the workflow run?
-	 * @param factory
-	 *            What class built this object?
-	 */
-	protected HelioSecurityContextDelegateImpl(RemoteRunDelegate run,
-			UsernamePrincipal owner, SecurityContextFactory factory) {
-		super(run, owner, factory);
-	}
-
-	private Log log = LogFactory.getLog("Taverna.Server.Worker");
-	/** The name of the HTTP header holding the CIS token. */
-	private static final String HELIO_CIS_TOKEN = "X-Helio-CIS";
-	private transient String helioToken;
-
-	@Override
-	public void initializeSecurityFromSOAPContext(MessageContext context) {
-		// does nothing
-		@SuppressWarnings("unchecked")
-		Map<String, List<String>> headers = (Map<String, List<String>>) context
-				.get(HTTP_REQUEST_HEADERS);
-		if (factory.supportHelioToken && headers.containsKey(HELIO_CIS_TOKEN))
-			helioToken = headers.get(HELIO_CIS_TOKEN).get(0);
-	}
-
-	@Override
-	public void initializeSecurityFromRESTContext(HttpHeaders context) {
-		// does nothing
-		MultivaluedMap<String, String> headers = context.getRequestHeaders();
-		if (factory.supportHelioToken && headers.containsKey(HELIO_CIS_TOKEN))
-			helioToken = headers.get(HELIO_CIS_TOKEN).get(0);
-	}
-
-	@Override
-	protected void conveyExtraSecuritySettings(RemoteSecurityContext rc)
-			throws RemoteException {
-		try {
-			if (factory.supportHelioToken && helioToken != null) {
-				if (factory.logSecurityDetails)
-					log.info("transfering HELIO CIS token: " + helioToken);
-				rc.setHelioToken(helioToken);
-			}
-		} finally {
-			helioToken = null;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java
deleted file mode 100644
index 1d485d8..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static java.security.Security.addProvider;
-import static java.security.Security.getProvider;
-import static java.security.Security.removeProvider;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
-
-import java.io.Serializable;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.logging.Log;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.beans.factory.annotation.Value;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.CertificateChainFetcher;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.utils.X500Utils;
-
-/**
- * Singleton factory. Really is a singleton (and is also very trivial); the
- * singleton-ness is just about limiting the number of instances of this around
- * even when lots of serialization is going on.
- * 
- * @see Serializable
- * @author Donal Fellows
- */
-public class SecurityContextFactory implements
-		org.taverna.server.master.interfaces.SecurityContextFactory {
-	private static final long serialVersionUID = 12345678987654321L;
-	private static SecurityContextFactory instance;
-	transient RunDBSupport db;
-	transient FilenameUtils fileUtils;
-	transient X500Utils x500Utils;
-	transient UriBuilderFactory uriSource;
-	transient CertificateChainFetcher certFetcher;
-	transient String httpRealm;
-	private transient PasswordIssuer passwordIssuer;
-	private transient BouncyCastleProvider provider;
-
-	/**
-	 * Whether to support HELIO CIS tokens.
-	 */
-	@Value("${helio.cis.enableTokenPassing}")
-	boolean supportHelioToken;
-
-	/**
-	 * Whether to log the details of security (passwords, etc).
-	 */
-	@Value("${log.security.details}")
-	boolean logSecurityDetails;
-
-	private Log log() {
-		return getLog("Taverna.Server.Worker.Security");
-	}
-
-	private void installAsInstance(SecurityContextFactory handle) {
-		instance = handle;
-	}
-
-	@PreDestroy
-	void removeAsSingleton() {
-		installAsInstance(null);
-		try {
-			if (provider != null)
-				removeProvider(provider.getName());
-		} catch (SecurityException e) {
-			log().warn(
-					"failed to remove BouncyCastle security provider; "
-							+ "might be OK if configured in environment", e);
-		}
-	}
-
-	@PostConstruct
-	void setAsSingleton() {
-		installAsInstance(this);
-		if (getProvider(PROVIDER_NAME) == null)
-			try {
-				provider = new BouncyCastleProvider();
-				if (addProvider(provider) == -1)
-					provider = null;
-			} catch (SecurityException e) {
-				log().warn(
-						"failed to install BouncyCastle security provider; "
-								+ "might be OK if already configured", e);
-				provider = null;
-			}
-	}
-
-	@Required
-	public void setRunDatabase(RunDBSupport db) {
-		this.db = db;
-	}
-
-	@Required
-	public void setCertificateFetcher(CertificateChainFetcher fetcher) {
-		this.certFetcher = fetcher;
-	}
-
-	@Required
-	public void setFilenameConverter(FilenameUtils fileUtils) {
-		this.fileUtils = fileUtils;
-	}
-
-	@Required
-	public void setX500Utils(X500Utils x500Utils) {
-		this.x500Utils = x500Utils;
-	}
-
-	@Required
-	public void setUriSource(UriBuilderFactory uriSource) {
-		this.uriSource = uriSource;
-	}
-
-	@Required
-	public void setHttpRealm(String realm) {
-		this.httpRealm = realm; //${http.realmName}
-	}
-
-	@Required
-	public void setPasswordIssuer(PasswordIssuer issuer) {
-		this.passwordIssuer = issuer;
-	}
-
-	@Override
-	public SecurityContextDelegate create(TavernaRun run,
-			UsernamePrincipal owner) throws Exception {
-		Log log = log();
-		if (log.isDebugEnabled())
-			log.debug("constructing security context delegate for " + owner);
-		RemoteRunDelegate rrd = (RemoteRunDelegate) run;
-		return new HelioSecurityContextDelegateImpl(rrd, owner, this);
-	}
-
-	private Object readResolve() {
-		if (instance == null)
-			installAsInstance(this);
-		return instance;
-	}
-
-	public String issueNewPassword() {
-		return passwordIssuer.issue();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
deleted file mode 100644
index f9f4d16..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.defaults.Default.NOTIFY_MESSAGE_FORMAT;
-
-import java.text.MessageFormat;
-
-import org.springframework.beans.factory.annotation.Required;
-
-/**
- * Completion notifier that sends messages by email.
- * 
- * @author Donal Fellows
- */
-public class SimpleFormattedCompletionNotifier implements CompletionNotifier {
-	@Required
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	/**
-	 * @param subject
-	 *            The subject of the notification email.
-	 */
-	@Required
-	public void setSubject(String subject) {
-		this.subject = subject;
-	}
-
-	/**
-	 * @param messageFormat
-	 *            The template for the body of the message to send. Parameter #0
-	 *            will be substituted with the ID of the job, and parameter #1
-	 *            will be substituted with the exit code.
-	 */
-	public void setMessageFormat(String messageFormat) {
-		this.format = new MessageFormat(messageFormat);
-	}
-
-	private String name;
-	private String subject;
-	private MessageFormat format = new MessageFormat(NOTIFY_MESSAGE_FORMAT);
-
-	@Override
-	public String makeCompletionMessage(String name, RemoteRunDelegate run,
-			int code) {
-		return format.format(new Object[] { name, code });
-	}
-
-	@Override
-	public String makeMessageSubject(String name, RemoteRunDelegate run,
-			int code) {
-		return subject;
-	}
-
-	@Override
-	public String getName() {
-		return name;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java
deleted file mode 100644
index a81e610..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import java.io.StringWriter;
-
-import org.apache.velocity.Template;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.VelocityEngine;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-
-public class VelocityCompletionNotifier implements CompletionNotifier {
-	private String subject;
-	private VelocityEngine engine;
-	private Template template;
-	private String name;
-	private String templateName;
-	private UriBuilderFactory ubf;
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * @param subject
-	 *            The subject of the notification email.
-	 */
-	@Required
-	public void setSubject(String subject) {
-		this.subject = subject;
-	}
-
-	/**
-	 * @param engine
-	 *            The configured Apache Velocity engine.
-	 */
-	@Required
-	public void setVelocityEngine(VelocityEngine engine) {
-		this.engine = engine;
-	}
-
-	/**
-	 * @param uriBuilderFactory
-	 *            The configured URI builder factory.
-	 */
-	@Required
-	public void setUriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
-		this.ubf = uriBuilderFactory;
-	}
-
-	/**
-	 * @param name
-	 *            The name of the template.
-	 */
-	@Required
-	public void setName(String name) {
-		this.name = name;
-		this.templateName = getClass().getName() + "_" + name + ".vtmpl";
-	}
-
-	private Template getTemplate() {
-		if (template == null)
-			synchronized(this) {
-				if (template == null)
-					template = engine.getTemplate(templateName);
-			}
-		return template;
-	}
-
-	@Override
-	public String makeCompletionMessage(String name, RemoteRunDelegate run,
-			int code) {
-		VelocityContext ctxt = new VelocityContext();
-		ctxt.put("id", name);
-		ctxt.put("uriBuilder", ubf.getRunUriBuilder(run));
-		ctxt.put("name", run.getName());
-		ctxt.put("creationTime", run.getCreationTimestamp());
-		ctxt.put("startTime", run.getStartTimestamp());
-		ctxt.put("finishTime", run.getFinishTimestamp());
-		ctxt.put("expiryTime", run.getExpiry());
-		ctxt.put("serverVersion", Version.JAVA);
-		for (Listener l : run.getListeners())
-			if (l.getName().equals("io")) {
-				for (String p : l.listProperties())
-					try {
-						ctxt.put("prop_" + p, l.getProperty(p));
-					} catch (NoListenerException e) {
-						// Ignore...
-					}
-				break;
-			}
-		StringWriter sw = new StringWriter();
-		getTemplate().merge(ctxt, sw);
-		return sw.toString();
-	}
-
-	@Override
-	public String makeMessageSubject(String name, RemoteRunDelegate run,
-			int code) {
-		return subject;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java
deleted file mode 100644
index 510c8d0..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-
-import java.net.URI;
-import java.util.List;
-
-import org.taverna.server.master.common.Status;
-
-/**
- * Profile of the getters and setters in a worker system. Ensures that the
- * persisted state matches the public view on the state model at least fairly
- * closely.
- * 
- * @author Donal Fellows
- */
-public interface WorkerModel extends PolicyLimits {
-
-	/**
-	 * @param defaultLifetime
-	 *            how long a workflow run should live by default, in minutes.
-	 */
-	public abstract void setDefaultLifetime(int defaultLifetime);
-
-	/**
-	 * @return how long a workflow run should live by default, in minutes.
-	 */
-	public abstract int getDefaultLifetime();
-
-	/**
-	 * @param maxRuns
-	 *            the maximum number of extant workflow runs
-	 */
-	public abstract void setMaxRuns(int maxRuns);
-
-	/**
-	 * @param factoryProcessNamePrefix
-	 *            the prefix used for factory processes in RMI
-	 */
-	public abstract void setFactoryProcessNamePrefix(
-			String factoryProcessNamePrefix);
-
-	/**
-	 * @return the prefix used for factory processes in RMI
-	 */
-	public abstract String getFactoryProcessNamePrefix();
-
-	/**
-	 * @param executeWorkflowScript
-	 *            the script to run to actually run a workflow
-	 */
-	public abstract void setExecuteWorkflowScript(String executeWorkflowScript);
-
-	/**
-	 * @return the script to run to actually run a workflow
-	 */
-	public abstract String getExecuteWorkflowScript();
-
-	/**
-	 * @param extraArgs
-	 *            the extra arguments to pass into the workflow runner
-	 */
-	public abstract void setExtraArgs(String[] extraArgs);
-
-	/**
-	 * @return the extra arguments to pass into the workflow runner
-	 */
-	public abstract String[] getExtraArgs();
-
-	/**
-	 * @param waitSeconds
-	 *            the number of seconds to wait for subprocesses to start
-	 */
-	public abstract void setWaitSeconds(int waitSeconds);
-
-	/**
-	 * @return the number of seconds to wait for subprocesses to start
-	 */
-	public abstract int getWaitSeconds();
-
-	/**
-	 * @param sleepMS
-	 *            milliseconds to wait between polling for a started
-	 *            subprocess's status
-	 */
-	public abstract void setSleepMS(int sleepMS);
-
-	/**
-	 * @return milliseconds to wait between polling for a started subprocess's
-	 *         status
-	 */
-	public abstract int getSleepMS();
-
-	/**
-	 * @param serverWorkerJar
-	 *            the full path name of the file system access worker
-	 *            subprocess's implementation JAR
-	 */
-	public abstract void setServerWorkerJar(String serverWorkerJar);
-
-	/**
-	 * @return the full path name of the file system access worker subprocess's
-	 *         implementation JAR
-	 */
-	public abstract String getServerWorkerJar();
-
-	/**
-	 * @param javaBinary
-	 *            the full path name to the Java binary to use
-	 */
-	public abstract void setJavaBinary(String javaBinary);
-
-	/**
-	 * @return the full path name to the Java binary to use
-	 */
-	public abstract String getJavaBinary();
-
-	/**
-	 * @param registryPort
-	 *            what port is the RMI registry on
-	 */
-	public abstract void setRegistryPort(int registryPort);
-
-	/**
-	 * @return what port is the RMI registry on
-	 */
-	public abstract int getRegistryPort();
-
-	/**
-	 * @param registryHost
-	 *            what host (network interface) is the RMI registry on
-	 */
-	public abstract void setRegistryHost(String registryHost);
-
-	/**
-	 * @return what host (network interface) is the RMI registry on
-	 */
-	public abstract String getRegistryHost();
-
-	/**
-	 * @param serverForkerJar
-	 *            the full path name of the impersonation engine's
-	 *            implementation JAR
-	 */
-	public abstract void setServerForkerJar(String serverForkerJar);
-
-	/**
-	 * @return the full path name of the impersonation engine's implementation
-	 *         JAR
-	 */
-	public abstract String getServerForkerJar();
-
-	/**
-	 * @param passwordFile
-	 *            the full path name of a file containing a password to use with
-	 *            sudo (or empty for none)
-	 */
-	public abstract void setPasswordFile(String passwordFile);
-
-	/**
-	 * @return the full path name of a file containing a password to use with
-	 *         sudo (or empty for none)
-	 */
-	public abstract String getPasswordFile();
-
-	/**
-	 * @param operatingLimit
-	 *            the maximum number of runs in the
-	 *            {@linkplain Status#Operating operating} state at once
-	 */
-	public abstract void setOperatingLimit(int operatingLimit);
-
-	@Override
-	void setPermittedWorkflowURIs(List<URI> permittedWorkflows);
-
-	/**
-	 * @return the full path name of the RMI registry subprocess's
-	 *         implementation JAR
-	 */
-	String getRegistryJar();
-
-	/**
-	 * @param rmiRegistryJar
-	 *            the full path name of the RMI registry subprocess's
-	 *            implementation JAR
-	 */
-	void setRegistryJar(String rmiRegistryJar);
-
-	/**
-	 * @return whether a run should generate provenance information by default
-	 */
-	boolean getGenerateProvenance();
-
-	/**
-	 * @param generateProvenance
-	 *            whether a run should generate provenance information by
-	 *            default
-	 */
-	void setGenerateProvenance(boolean generateProvenance);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java
deleted file mode 100644
index e96b794..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-/**
- * A Taverna Server back-end that works by forking off workflow executors.
- */
-package org.taverna.server.master.worker;
-/*
- * 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.
- */
-


[03/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/WorkerCore.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/WorkerCore.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/WorkerCore.java
new file mode 100644
index 0000000..4aa6605
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/WorkerCore.java
@@ -0,0 +1,931 @@
+/*
+ */
+package org.taverna.server.localworker.impl;
+/*
+ * 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.
+ */
+
+import static java.io.File.createTempFile;
+import static java.io.File.pathSeparator;
+import static java.lang.Boolean.parseBoolean;
+import static java.lang.Double.parseDouble;
+import static java.lang.Integer.parseInt;
+import static java.lang.Long.parseLong;
+import static java.lang.Runtime.getRuntime;
+import static java.lang.System.out;
+import static java.net.InetAddress.getLocalHost;
+import static org.apache.commons.io.FileUtils.forceDelete;
+import static org.apache.commons.io.FileUtils.sizeOfDirectory;
+import static org.apache.commons.io.FileUtils.write;
+import static org.apache.commons.io.IOUtils.copy;
+import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_DIRECTORY;
+import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_PASSWORD;
+import static org.taverna.server.localworker.api.Constants.DEATH_TIME;
+import static org.taverna.server.localworker.api.Constants.DEFAULT_LISTENER_NAME;
+import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
+import static org.taverna.server.localworker.api.Constants.START_WAIT_TIME;
+import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
+import static org.taverna.server.localworker.api.Constants.TIME;
+import static org.taverna.server.localworker.impl.Status.Aborted;
+import static org.taverna.server.localworker.impl.Status.Completed;
+import static org.taverna.server.localworker.impl.Status.Failed;
+import static org.taverna.server.localworker.impl.Status.Held;
+import static org.taverna.server.localworker.impl.Status.Started;
+import static org.taverna.server.localworker.impl.TavernaRunManager.interactionFeedPath;
+import static org.taverna.server.localworker.impl.TavernaRunManager.interactionHost;
+import static org.taverna.server.localworker.impl.TavernaRunManager.interactionPort;
+import static org.taverna.server.localworker.impl.TavernaRunManager.interactionWebdavPath;
+import static org.taverna.server.localworker.impl.WorkerCore.pmap;
+import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
+import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
+import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
+import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.ws.Holder;
+
+import org.apache.taverna.server.usagerecord.JobUsageRecord;
+import org.taverna.server.localworker.api.RunAccounting;
+import org.taverna.server.localworker.api.Worker;
+import org.taverna.server.localworker.impl.utils.TimingOutTask;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+/**
+ * The core class that connects to a Taverna command-line workflow execution
+ * engine. This implementation always registers a single listener, &lquo;
+ * <tt>io</tt> &rquo;, with two properties representing the stdout and stderr of
+ * the run and one representing the exit code. The listener is
+ * remote-accessible. It does not support attaching any other listeners.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+public class WorkerCore extends UnicastRemoteObject implements Worker,
+		RemoteListener {
+	@Nonnull
+	static final Map<String, Property> pmap = new HashMap<>();
+	/**
+	 * Regular expression to extract the detailed timing information from the
+	 * output of /usr/bin/time
+	 */
+	@Nonnull
+	private static final Pattern TimeRE;
+	static {
+		final String TIMERE = "([0-9.:]+)";
+		final String TERMS = "(real|user|system|sys|elapsed)";
+		TimeRE = Pattern.compile(TIMERE + " *" + TERMS + "[ \t]*" + TIMERE
+				+ " *" + TERMS + "[ \t]*" + TIMERE + " *" + TERMS);
+	}
+
+	/**
+	 * Environment variables to remove before any fork (because they're large or
+	 * potentially leaky).
+	 */
+	// TODO Conduct a proper survey of what to remove
+	@Nonnull
+	private static final String[] ENVIRONMENT_TO_REMOVE = { "SUDO_COMMAND",
+			"SUDO_USER", "SUDO_GID", "SUDO_UID", "DISPLAY", "LS_COLORS",
+			"XFILESEARCHPATH", "SSH_AGENT_PID", "SSH_AUTH_SOCK" };
+
+	@Nullable
+	Process subprocess;
+	@Nonnull
+	final StringWriter stdout;
+	@Nonnull
+	final StringWriter stderr;
+	@Nullable
+	Integer exitCode;
+	boolean readyToSendEmail;
+	@Nullable
+	String emailAddress;
+	@Nullable
+	Date start;
+	@Nonnull
+	final RunAccounting accounting;
+	@Nonnull
+	final Holder<Integer> pid;
+
+	private boolean finished;
+	@Nullable
+	private JobUsageRecord ur;
+	@Nullable
+	private File wd;
+	@Nullable
+	private UsageRecordReceiver urreceiver;
+	@Nullable
+	private File workflowFile;
+	private boolean stopped;
+
+	/**
+	 * @param accounting
+	 *            Object that looks after how many runs are executing.
+	 * @throws RemoteException
+	 */
+	public WorkerCore(@Nonnull RunAccounting accounting) throws RemoteException {
+		super();
+		stdout = new StringWriter();
+		stderr = new StringWriter();
+		pid = new Holder<>();
+		this.accounting = accounting;
+	}
+
+	private int getPID() {
+		synchronized (pid) {
+			if (pid.value == null)
+				return -1;
+			return pid.value;
+		}
+	}
+
+	/**
+	 * Fire up the workflow. This causes a transition into the operating state.
+	 * 
+	 * @param executeWorkflowCommand
+	 *            The command to run to execute the workflow.
+	 * @param workflow
+	 *            The workflow document to execute.
+	 * @param workingDir
+	 *            What directory to use as the working directory.
+	 * @param inputBaclava
+	 *            The baclava file to use for inputs, or <tt>null</tt> to use
+	 *            the other <b>input*</b> arguments' values.
+	 * @param inputFiles
+	 *            A mapping of input names to files that supply them. Note that
+	 *            we assume that nothing mapped here will be mapped in
+	 *            <b>inputValues</b>.
+	 * @param inputValues
+	 *            A mapping of input names to values to supply to them. Note
+	 *            that we assume that nothing mapped here will be mapped in
+	 *            <b>inputFiles</b>.
+	 * @param outputBaclava
+	 *            What baclava file to write the output from the workflow into,
+	 *            or <tt>null</tt> to have it written into the <tt>out</tt>
+	 *            subdirectory.
+	 * @param token
+	 *            The name of the workflow run.
+	 * @return <tt>true</tt> if the worker started, or <tt>false</tt> if a
+	 *         timeout occurred.
+	 * @throws IOException
+	 *             If any of quite a large number of things goes wrong.
+	 */
+	@Override
+	public boolean initWorker(
+			@Nonnull final LocalWorker local,
+			@Nonnull final String executeWorkflowCommand,
+			@Nonnull final byte[] workflow,
+			@Nonnull final File workingDir,
+			@Nullable final File inputBaclava,
+			@Nonnull final Map<String, File> inputFiles,
+			@Nonnull final Map<String, String> inputValues, 
+			@Nonnull final Map<String, String> inputDelimiters,
+			@Nullable final File outputBaclava,
+			@Nonnull final File securityDir,
+			@Nullable final char[] password,
+			final boolean generateProvenance,
+			@Nonnull final Map<String, String> environment,
+			@Nullable final String token,
+			@Nonnull final List<String> runtime) throws IOException {
+		try {
+			new TimingOutTask() {
+				@Override
+				public void doIt() throws IOException {
+					startExecutorSubprocess(
+							createProcessBuilder(local, executeWorkflowCommand,
+									workflow, workingDir, inputBaclava,
+									inputFiles, inputValues, inputDelimiters,
+									outputBaclava, securityDir, password,
+									generateProvenance, environment, token,
+									runtime), password);
+				}
+			}.doOrTimeOut(START_WAIT_TIME);
+		} catch (IOException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new IOException(e);
+		}
+		return subprocess != null;
+	}
+
+	private void startExecutorSubprocess(@Nonnull ProcessBuilder pb,
+			@Nullable char[] password) throws IOException {
+		// Start the subprocess
+		out.println("starting " + pb.command() + " in directory "
+				+ pb.directory() + " with environment " + pb.environment());
+		subprocess = pb.start();
+		if (subprocess == null)
+			throw new IOException("unknown failure creating process");
+		start = new Date();
+		accounting.runStarted();
+
+		// Capture its stdout and stderr
+		new AsyncCopy(subprocess.getInputStream(), stdout, pid);
+		new AsyncCopy(subprocess.getErrorStream(), stderr);
+		if (password != null)
+			new PasswordWriterThread(subprocess, password);
+	}
+
+	/**
+	 * Assemble the process builder. Does not launch the subprocess.
+	 * 
+	 * @param local
+	 *            The local worker container.
+	 * @param executeWorkflowCommand
+	 *            The reference to the workflow engine implementation.
+	 * @param workflow
+	 *            The workflow to execute.
+	 * @param workingDir
+	 *            The working directory to use.
+	 * @param inputBaclava
+	 *            What file to read a baclava document from (or <tt>null</tt>)
+	 * @param inputFiles
+	 *            The mapping from inputs to files.
+	 * @param inputValues
+	 *            The mapping from inputs to literal values.
+	 * @param outputBaclava
+	 *            What file to write a baclava document to (or <tt>null</tt>)
+	 * @param securityDir
+	 *            The credential manager directory.
+	 * @param password
+	 *            The password for the credential manager.
+	 * @param environment
+	 *            The seed environment
+	 * @param token
+	 *            The run identifier that the server wants to use.
+	 * @param runtime
+	 *            Any runtime parameters to Java.
+	 * @return The configured process builder.
+	 * @throws IOException
+	 *             If file handling fails
+	 * @throws UnsupportedEncodingException
+	 *             If we can't encode any text (unlikely)
+	 * @throws FileNotFoundException
+	 *             If we can't write the workflow out (unlikely)
+	 */
+	@Nonnull
+	ProcessBuilder createProcessBuilder(@Nonnull LocalWorker local,
+			@Nonnull String executeWorkflowCommand, @Nonnull byte[] workflow,
+			@Nonnull File workingDir, @Nullable File inputBaclava,
+			@Nonnull Map<String, File> inputFiles,
+			@Nonnull Map<String, String> inputValues,
+			@Nonnull Map<String, String> inputDelimiters,
+			@Nullable File outputBaclava, @Nonnull File securityDir,
+			@Nonnull char[] password, boolean generateProvenance,
+			@Nonnull Map<String, String> environment, @Nonnull String token,
+			@Nonnull List<String> runtime) throws IOException,
+			UnsupportedEncodingException, FileNotFoundException {
+		ProcessBuilder pb = new ProcessBuilder();
+		pb.command().add(TIME);
+		/*
+		 * WARNING! HERE THERE BE DRAGONS! BE CAREFUL HERE!
+		 * 
+		 * Work around _Maven_ bug with permissions in zip files! The executable
+		 * bit is stripped by Maven's handling of file permissions, and there's
+		 * no practical way to work around it without massively increasing the
+		 * pain in other ways. Only want this on Unix - Windows isn't affected
+		 * by this - so we use the file separator as a proxy for whether this is
+		 * a true POSIX system. Ugly! Ugly ugly ugly...
+		 * 
+		 * http://jira.codehaus.org/browse/MASSEMBLY-337 is relevant, but not
+		 * the whole story as we don't want to use a non-standard packaging
+		 * method as there's a real chance of it going wrong in an unexpected
+		 * way then. Other parts of the story are that the executable bit isn't
+		 * preserved when unpacking with the dependency plugin, and there's no
+		 * way to be sure that the servlet container will preserve the bit
+		 * either (as that's probably using a Java-based ZIP engine).
+		 */
+		if (File.separatorChar == '/')
+			pb.command().add("/bin/sh");
+		pb.command().add(executeWorkflowCommand);
+		if (runtime != null)
+			pb.command().addAll(runtime);
+
+		// Enable verbose logging
+		pb.command().add("-logfile");
+		pb.command().add(
+				new File(new File(workingDir, "logs"), "detail.log")
+						.getAbsolutePath());
+
+		if (securityDir != null) {
+			pb.command().add(CREDENTIAL_MANAGER_DIRECTORY);
+			pb.command().add(securityDir.getAbsolutePath());
+			out.println("security dir location: " + securityDir);
+		}
+		if (password != null) {
+			pb.command().add(CREDENTIAL_MANAGER_PASSWORD);
+			out.println("password of length " + password.length
+					+ " will be written to subprocess stdin");
+		}
+
+		// Add arguments denoting inputs
+		if (inputBaclava != null) {
+			pb.command().add("-inputdoc");
+			pb.command().add(inputBaclava.getAbsolutePath());
+			if (!inputBaclava.exists())
+				throw new IOException("input baclava file doesn't exist");
+		} else {
+			for (Entry<String, File> port : inputFiles.entrySet()) {
+				if (port.getValue() == null)
+					continue;
+				pb.command().add("-inputfile");
+				pb.command().add(port.getKey());
+				pb.command().add(port.getValue().getAbsolutePath());
+				if (!port.getValue().exists())
+					throw new IOException("input file for port \"" + port
+							+ "\" doesn't exist");
+			}
+			for (Entry<String, String> port : inputValues.entrySet()) {
+				if (port.getValue() == null)
+					continue;
+				pb.command().add("-inputfile");
+				pb.command().add(port.getKey());
+				File f = createTempFile(".tav_in_", null, workingDir);
+				pb.command().add(f.getAbsolutePath());
+				write(f, port.getValue(), "UTF-8");
+			}
+			for (Entry<String, String> delim : inputDelimiters.entrySet()) {
+				if (delim.getValue() == null)
+					continue;
+				pb.command().add("-inputdelimiter");
+				pb.command().add(delim.getKey());
+				pb.command().add(delim.getValue());
+			}
+		}
+
+		// Add arguments denoting outputs
+		if (outputBaclava != null) {
+			pb.command().add("-outputdoc");
+			pb.command().add(outputBaclava.getAbsolutePath());
+			if (!outputBaclava.getParentFile().exists())
+				throw new IOException(
+						"parent directory of output baclava file does not exist");
+			if (outputBaclava.exists())
+				throw new IOException("output baclava file exists");
+			// Provenance cannot be supported when using baclava output
+		} else {
+			File out = new File(workingDir, "out");
+			if (!out.mkdir())
+				throw new IOException("failed to make output directory \"out\"");
+			// Taverna needs the dir to *not* exist now
+			forceDelete(out);
+			pb.command().add("-outputdir");
+			pb.command().add(out.getAbsolutePath());
+			// Enable provenance generation
+			if (generateProvenance) {
+				pb.command().add("-embedded");
+				pb.command().add("-provenance");
+				pb.command().add("-provbundle");
+				pb.command().add("out.bundle.zip");
+			}
+		}
+
+		// Add an argument holding the workflow
+		File tmp = createTempFile(".wf_", ".scufl2", workingDir);
+		try (OutputStream os = new FileOutputStream(tmp)) {
+			os.write(workflow);
+		}
+		pb.command().add(workflowFile.getAbsolutePath());
+
+		// Indicate what working directory to use
+		pb.directory(workingDir);
+		wd = workingDir;
+
+		Map<String, String> env = pb.environment();
+		for (String name : ENVIRONMENT_TO_REMOVE)
+			env.remove(name);
+
+		// Merge any options we have had imposed on us from outside
+		env.putAll(environment);
+
+		// Patch the environment to deal with TAVUTILS-17
+		assert env.get("PATH") != null;
+		env.put("PATH", new File(System.getProperty("java.home"), "bin")
+				+ pathSeparator + env.get("PATH"));
+		// Patch the environment to deal with TAVSERV-189
+		env.put("TAVERNA_APPHOME", workingDir.getCanonicalPath());
+		// Patch the environment to deal with TAVSERV-224
+		env.put("TAVERNA_RUN_ID", token);
+		if (interactionHost != null || local.interactionFeedURL != null
+				|| local.webdavURL != null) {
+			env.put("INTERACTION_HOST", makeInterHost(local.interactionFeedURL));
+			env.put("INTERACTION_PORT", makeInterPort(local.interactionFeedURL));
+			env.put("INTERACTION_FEED", makeInterPath(local.interactionFeedURL));
+			env.put("INTERACTION_WEBDAV",
+					local.webdavURL != null ? local.webdavURL.getPath()
+							: interactionWebdavPath);
+			String pub = makeInterPublish(local.publishURL);
+			if (pub != null && !pub.isEmpty())
+				env.put("INTERACTION_PUBLISH", pub);
+		}
+		return pb;
+	}
+
+	@Nullable
+	private static String makeInterHost(@Nullable URL url) {
+		if (url == null)
+			return interactionHost;
+		return url.getProtocol() + "://" + url.getHost();
+	}
+
+	@Nullable
+	private static String makeInterPort(@Nullable URL url) {
+		if (url == null)
+			return interactionPort;
+		int port = url.getPort();
+		if (port == -1)
+			port = url.getDefaultPort();
+		return Integer.toString(port);
+	}
+
+	@Nullable
+	private static String makeInterPublish(@Nullable URL url)
+			throws IOException {
+		if (url == null)
+			return null;
+		try {
+			URI uri = url.toURI();
+			int port = uri.getPort();
+			if (port == -1)
+				return uri.getScheme() + "://" + uri.getHost();
+			else
+				return uri.getScheme() + "://" + uri.getHost() + ":" + port;
+		} catch (URISyntaxException e) {
+			throw new IOException("problem constructing publication url", e);
+		}
+	}
+
+	@Nullable
+	private static String makeInterPath(@Nullable URL url) {
+		if (url == null)
+			return interactionFeedPath;
+		return url.getPath();
+	}
+
+	/**
+	 * Kills off the subprocess if it exists and is alive.
+	 */
+	@Override
+	public void killWorker() {
+		if (!finished && subprocess != null) {
+			final Holder<Integer> code = new Holder<>();
+			for (TimingOutTask tot : new TimingOutTask[] { new TimingOutTask() {
+				/** Check if the workflow terminated of its own accord */
+				@Override
+				public void doIt() throws IOException {
+					code.value = subprocess.exitValue();
+					accounting.runCeased();
+					buildUR(code.value == 0 ? Completed : Failed, code.value);
+				}
+			}, new TimingOutTask() {
+				/** Tell the workflow to stop */
+				@Override
+				public void doIt() throws IOException {
+					code.value = killNicely();
+					accounting.runCeased();
+					buildUR(code.value == 0 ? Completed : Aborted, code.value);
+				}
+			}, new TimingOutTask() {
+				/** Kill the workflow, kill it with fire */
+				@Override
+				public void doIt() throws IOException {
+					code.value = killHard();
+					accounting.runCeased();
+					buildUR(code.value == 0 ? Completed : Aborted, code.value);
+				}
+			} }) {
+				try {
+					tot.doOrTimeOut(DEATH_TIME);
+				} catch (Exception e) {
+				}
+				if (code.value != null)
+					break;
+			}
+			finished = true;
+			setExitCode(code.value);
+			readyToSendEmail = true;
+		}
+	}
+
+	/**
+	 * Integrated spot to handle writing/logging of the exit code.
+	 * 
+	 * @param code
+	 *            The exit code.
+	 */
+	private void setExitCode(int code) {
+		exitCode = code;
+		if (code > 256 - 8) {
+			out.println("workflow aborted, Raven issue = " + (code - 256));
+		} else if (code > 128) {
+			out.println("workflow aborted, signal=" + (code - 128));
+		} else {
+			out.println("workflow exited, code=" + code);
+		}
+	}
+
+	@Nonnull
+	private JobUsageRecord newUR() throws DatatypeConfigurationException {
+		try {
+			if (wd != null)
+				return new JobUsageRecord(wd.getName());
+		} catch (RuntimeException e) {
+		}
+		return new JobUsageRecord("unknown");
+	}
+
+	/**
+	 * Fills in the accounting information from the exit code and stderr.
+	 * 
+	 * @param exitCode
+	 *            The exit code from the program.
+	 */
+	private void buildUR(@Nonnull Status status, int exitCode) {
+		try {
+			Date now = new Date();
+			long user = -1, sys = -1, real = -1;
+			Matcher m = TimeRE.matcher(stderr.toString());
+			ur = newUR();
+			while (m.find())
+				for (int i = 1; i < 6; i += 2)
+					if (m.group(i + 1).equals("user"))
+						user = parseDuration(m.group(i));
+					else if (m.group(i + 1).equals("sys")
+							|| m.group(i + 1).equals("system"))
+						sys = parseDuration(m.group(i));
+					else if (m.group(i + 1).equals("real")
+							|| m.group(i + 1).equals("elapsed"))
+						real = parseDuration(m.group(i));
+			if (user != -1)
+				ur.addCpuDuration(user).setUsageType("user");
+			if (sys != -1)
+				ur.addCpuDuration(sys).setUsageType("system");
+			ur.addUser(System.getProperty("user.name"), null);
+			ur.addStartAndEnd(start, now);
+			if (real != -1)
+				ur.addWallDuration(real);
+			else
+				ur.addWallDuration(now.getTime() - start.getTime());
+			ur.setStatus(status.toString());
+			ur.addHost(getLocalHost().getHostName());
+			ur.addResource("exitcode", Integer.toString(exitCode));
+			ur.addDisk(sizeOfDirectory(wd)).setStorageUnit("B");
+			if (urreceiver != null)
+				urreceiver.acceptUsageRecord(ur.marshal());
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	private long parseDuration(@Nonnull String durationString) {
+		try {
+			return (long) (parseDouble(durationString) * 1000);
+		} catch (NumberFormatException nfe) {
+			// Not a double; maybe MM:SS.mm or HH:MM:SS.mm
+		}
+		long dur = 0;
+		for (String d : durationString.split(":"))
+			try {
+				dur = 60 * dur + parseLong(d);
+			} catch (NumberFormatException nfe) {
+				// Assume that only one thing is fractional, and that it is last
+				return 60000 * dur + (long) (parseDouble(d) * 1000);
+			}
+		return dur * 1000;
+	}
+
+	private void signal(@Nonnull String signal) throws Exception {
+		int pid = getPID();
+		if (pid > 0
+				&& getRuntime().exec("kill -" + signal + " " + pid).waitFor() == 0)
+			return;
+		throw new Exception("failed to send signal " + signal + " to process "
+				+ pid);
+	}
+
+	@Nullable
+	private Integer killNicely() {
+		try {
+			signal("TERM");
+			return subprocess.waitFor();
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	@Nullable
+	private Integer killHard() {
+		try {
+			signal("QUIT");
+			return subprocess.waitFor();
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/**
+	 * Move the worker out of the stopped state and back to operating.
+	 * 
+	 * @throws Exception
+	 *             if it fails.
+	 */
+	@Override
+	public void startWorker() throws Exception {
+		signal("CONT");
+		stopped = false;
+	}
+
+	/**
+	 * Move the worker into the stopped state from the operating state.
+	 * 
+	 * @throws Exception
+	 *             if it fails.
+	 */
+	@Override
+	public void stopWorker() throws Exception {
+		signal("STOP");
+		stopped = true;
+	}
+
+	/**
+	 * @return The status of the workflow run. Note that this can be an
+	 *         expensive operation.
+	 */
+	@Override
+	public RemoteStatus getWorkerStatus() {
+		if (subprocess == null)
+			return Initialized;
+		if (finished)
+			return Finished;
+		try {
+			setExitCode(subprocess.exitValue());
+		} catch (IllegalThreadStateException e) {
+			if (stopped)
+				return Stopped;
+			return Operating;
+		}
+		finished = true;
+		readyToSendEmail = true;
+		accounting.runCeased();
+		buildUR(exitCode.intValue() == 0 ? Completed : Failed, exitCode);
+		return Finished;
+	}
+
+	@Override
+	public String getConfiguration() {
+		return "";
+	}
+
+	@Override
+	public String getName() {
+		return DEFAULT_LISTENER_NAME;
+	}
+
+	@Override
+	public String getProperty(String propName) throws RemoteException {
+		switch (Property.is(propName)) {
+		case STDOUT:
+			return stdout.toString();
+		case STDERR:
+			return stderr.toString();
+		case EXIT_CODE:
+			return (exitCode == null) ? "" : exitCode.toString();
+		case EMAIL:
+			return emailAddress;
+		case READY_TO_NOTIFY:
+			return Boolean.toString(readyToSendEmail);
+		case USAGE:
+			try {
+				JobUsageRecord toReturn;
+				if (subprocess == null) {
+					toReturn = newUR();
+					toReturn.setStatus(Held.toString());
+				} else if (ur == null) {
+					toReturn = newUR();
+					toReturn.setStatus(Started.toString());
+					toReturn.addStartAndEnd(start, new Date());
+					toReturn.addUser(System.getProperty("user.name"), null);
+				} else {
+					toReturn = ur;
+				}
+				/*
+				 * Note that this record is not to be pushed to the server. That
+				 * is done elsewhere (when a proper record is produced)
+				 */
+				return toReturn.marshal();
+			} catch (Exception e) {
+				e.printStackTrace();
+				return "";
+			}
+		default:
+			throw new RemoteException("unknown property");
+		}
+	}
+
+	@Override
+	public String getType() {
+		return DEFAULT_LISTENER_NAME;
+	}
+
+	@Override
+	public String[] listProperties() {
+		return Property.names();
+	}
+
+	@Override
+	public void setProperty(String propName, String value)
+			throws RemoteException {
+		switch (Property.is(propName)) {
+		case EMAIL:
+			emailAddress = value;
+			return;
+		case READY_TO_NOTIFY:
+			readyToSendEmail = parseBoolean(value);
+			return;
+		case STDOUT:
+		case STDERR:
+		case EXIT_CODE:
+		case USAGE:
+			throw new RemoteException("property is read only");
+		default:
+			throw new RemoteException("unknown property");
+		}
+	}
+
+	@Override
+	public RemoteListener getDefaultListener() {
+		return this;
+	}
+
+	@Override
+	public void setURReceiver(@Nonnull UsageRecordReceiver receiver) {
+		urreceiver = receiver;
+	}
+
+	@Override
+	public void deleteLocalResources() throws ImplementationException {
+		try {
+			if (workflowFile != null && workflowFile.getParentFile().exists())
+				forceDelete(workflowFile);
+		} catch (IOException e) {
+			throw new ImplementationException("problem deleting workflow file",
+					e);
+		}
+	}
+}
+
+/**
+ * An engine for asynchronously copying from an {@link InputStream} to a
+ * {@link Writer}.
+ * 
+ * @author Donal Fellows
+ */
+class AsyncCopy extends Thread {
+	@Nonnull
+	private BufferedReader from;
+	@Nonnull
+	private Writer to;
+	@Nullable
+	private Holder<Integer> pidHolder;
+
+	AsyncCopy(@Nonnull InputStream from, @Nonnull Writer to)
+			throws UnsupportedEncodingException {
+		this(from, to, null);
+	}
+
+	AsyncCopy(@Nonnull InputStream from, @Nonnull Writer to,
+			@Nullable Holder<Integer> pid) throws UnsupportedEncodingException {
+		this.from = new BufferedReader(new InputStreamReader(from,
+				SYSTEM_ENCODING));
+		this.to = to;
+		this.pidHolder = pid;
+		setDaemon(true);
+		start();
+	}
+
+	@Override
+	public void run() {
+		try {
+			if (pidHolder != null) {
+				String line = from.readLine();
+				if (line.matches("^pid:\\d+$"))
+					synchronized (pidHolder) {
+						pidHolder.value = parseInt(line.substring(4));
+					}
+				else
+					to.write(line + System.getProperty("line.separator"));
+			}
+			copy(from, to);
+		} catch (IOException e) {
+		}
+	}
+}
+
+/**
+ * A helper for asynchronously writing a password to a subprocess's stdin.
+ * 
+ * @author Donal Fellows
+ */
+class PasswordWriterThread extends Thread {
+	private OutputStream to;
+	private char[] chars;
+
+	PasswordWriterThread(@Nonnull Process to, @Nonnull char[] chars) {
+		this.to = to.getOutputStream();
+		assert chars != null;
+		this.chars = chars;
+		setDaemon(true);
+		start();
+	}
+
+	@Override
+	public void run() {
+		try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(to,
+				SYSTEM_ENCODING))) {
+			pw.println(chars);
+		} catch (UnsupportedEncodingException e) {
+			// Not much we can do here
+			e.printStackTrace();
+		} finally {
+			/*
+			 * We don't trust GC to clear password from memory. We also take
+			 * care not to clear the default password!
+			 */
+			if (chars != KEYSTORE_PASSWORD)
+				Arrays.fill(chars, '\00');
+		}
+	}
+}
+
+enum Property {
+	STDOUT("stdout"), STDERR("stderr"), EXIT_CODE("exitcode"), READY_TO_NOTIFY(
+			"readyToNotify"), EMAIL("notificationAddress"), USAGE("usageRecord");
+
+	private String s;
+
+	private Property(String s) {
+		this.s = s;
+		pmap.put(s, this);
+	}
+
+	@Override
+	public String toString() {
+		return s;
+	}
+
+	public static Property is(@Nonnull String s) {
+		return pmap.get(s);
+	}
+
+	@Nonnull
+	public static String[] names() {
+		return pmap.keySet().toArray(new String[pmap.size()]);
+	}
+}
+
+enum Status {
+	Aborted, Completed, Failed, Held, Queued, Started, Suspended
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/FilenameVerifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/FilenameVerifier.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/FilenameVerifier.java
new file mode 100644
index 0000000..fa2e117
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/FilenameVerifier.java
@@ -0,0 +1,169 @@
+/*
+ */
+package org.taverna.server.localworker.impl.utils;
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Utility class that handles filename validation on different target platforms.
+ * 
+ * @author Donal Fellows.
+ */
+public abstract class FilenameVerifier {
+	private FilenameVerifier(){}
+
+	static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
+
+	@SuppressWarnings("serial")
+	private static final Set<String> ILLEGAL_NAMES = new HashSet<String>(){{
+		add("");
+		add("..");
+		add(".");
+		if (IS_WINDOWS) {
+			add("con");
+			add("prn");
+			add("nul");
+			add("aux");
+			for (int i = 1; i <= 9; i++) {
+				add("com" + i);
+				add("lpt" + i);
+			}
+		}
+	}};
+	@SuppressWarnings("serial")
+	private static final Set<Character> ILLEGAL_CHARS = new HashSet<Character>(){{
+		add('/');
+		for (char i=0 ; i<32 ; i++)
+			add(i);
+		if (IS_WINDOWS) {
+			add('\\');
+			add('>');
+			add('<');
+			add(':');
+			add('"');
+			add('|');
+			add('?');
+			add('*');
+		} else {
+			add(' '); // whitespace; too much trouble from these
+			add('\t');
+			add('\r');
+			add('\n');
+		}
+	}};
+	@SuppressWarnings("serial")
+	private static final Set<String> ILLEGAL_PREFIXES = new HashSet<String>(){{
+		if (IS_WINDOWS) {
+			add("con.");
+			add("prn.");
+			add("nul.");
+			add("aux.");
+			for (int i = 1; i <= 9; i++) {
+				add("com" + i + ".");
+				add("lpt" + i + ".");
+			}
+		}
+	}};
+	@SuppressWarnings("serial")
+	private static final Set<String> ILLEGAL_SUFFIXES = new HashSet<String>(){{
+		if (IS_WINDOWS) {
+			add(" ");
+			add(".");
+		}
+	}};
+
+	/**
+	 * Construct a file handle, applying platform-specific filename validation
+	 * rules in the process.
+	 * 
+	 * @param dir
+	 *            The directory acting as a root, which is assumed to be
+	 *            correctly named. May be <tt>null</tt>.
+	 * @param names
+	 *            The names of filename fragments to apply the checks to. Must
+	 *            have at least one value.
+	 * @return The file handle. Never <tt>null</tt>.
+	 * @throws IOException
+	 *             If validation fails.
+	 */
+	public static File getValidatedFile(File dir, String... names)
+			throws IOException {
+		if (names.length == 0)
+			throw new IOException("empty filename");
+		File f = dir;
+		for (String name : names) {
+			String low = name.toLowerCase();
+			if (ILLEGAL_NAMES.contains(low))
+				throw new IOException("illegal filename");
+			for (char c : ILLEGAL_CHARS)
+				if (low.indexOf(c) >= 0)
+					throw new IOException("illegal filename");
+			for (String s : ILLEGAL_PREFIXES)
+				if (low.startsWith(s))
+					throw new IOException("illegal filename");
+			for (String s : ILLEGAL_SUFFIXES)
+				if (low.endsWith(s))
+					throw new IOException("illegal filename");
+			f = new File(f, name);
+		}
+		assert f != null;
+		return f;
+	}
+
+	/**
+	 * Create a file handle where the underlying file must exist.
+	 * 
+	 * @param dir
+	 *            The directory that will contain the file.
+	 * @param name
+	 *            The name of the file; will be validated.
+	 * @return The handle.
+	 * @throws IOException
+	 *             If validation fails or the file doesn't exist.
+	 */
+	public static File getValidatedExistingFile(File dir, String name)
+			throws IOException {
+		File f = getValidatedFile(dir, name);
+		if (!f.exists())
+			throw new IOException("doesn't exist");
+		return f;
+	}
+
+	/**
+	 * Create a file handle where the underlying file must <i>not</i> exist.
+	 * 
+	 * @param dir
+	 *            The directory that will contain the file.
+	 * @param name
+	 *            The name of the file; will be validated.
+	 * @return The handle. The file will not be created by this method.
+	 * @throws IOException
+	 *             If validation fails or the file does exist.
+	 */
+	public static File getValidatedNewFile(File dir, String name)
+			throws IOException {
+		File f = getValidatedFile(dir, name);
+		if (f.exists())
+			throw new IOException("already exists");
+		return f;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/TimingOutTask.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/TimingOutTask.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/TimingOutTask.java
new file mode 100644
index 0000000..c5b1b7b
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/TimingOutTask.java
@@ -0,0 +1,56 @@
+package org.taverna.server.localworker.impl.utils;
+/*
+ * 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.
+ */
+
+import javax.annotation.Nullable;
+
+/**
+ * A class that handles running a task that can take some time.
+ * 
+ * @author Donal Fellows
+ * 
+ */
+public abstract class TimingOutTask extends Thread {
+	public abstract void doIt() throws Exception;
+
+	@Nullable
+	private Exception ioe;
+
+	@Override
+	public final void run() {
+		try {
+			doIt();
+		} catch (Exception ioe) {
+			this.ioe = ioe;
+		}
+	}
+
+	public TimingOutTask() {
+		this.setDaemon(true);
+	}
+
+	public void doOrTimeOut(long timeout) throws Exception {
+		start();
+		try {
+			join(timeout);
+		} catch (InterruptedException e) {
+			interrupt();
+		}
+		if (ioe != null)
+			throw ioe;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
deleted file mode 100644
index 4ee24ad..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.api;
-/*
- * 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.
- */
-
-import static java.nio.charset.Charset.defaultCharset;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * The defaults associated with this worker, together with various other
- * constants.
- * 
- * @author Donal Fellows
- */
-public abstract class Constants {
-	/**
-	 * Subdirectories of the working directory to create by default.
-	 */
-	public static final String[] SUBDIR_LIST = { "conf", "externaltool", "feed",
-			"interactions", "lib", "logs", "plugins", "repository", "var" };
-
-	/** The name of the default encoding for characters on this machine. */
-	public static final String SYSTEM_ENCODING = defaultCharset().name();
-
-	/**
-	 * Password to use to encrypt security information. This default is <7 chars
-	 * to work even without Unlimited Strength JCE.
-	 */
-	public static final char[] KEYSTORE_PASSWORD = { 'c', 'h', 'a', 'n', 'g', 'e' };
-
-	/**
-	 * The name of the directory (in the home directory) where security settings
-	 * will be written.
-	 */
-	public static final String SECURITY_DIR_NAME = ".taverna-server-security";
-
-	/** The name of the file that will be the created keystore. */
-	public static final String KEYSTORE_FILE = "t2keystore.ubr";
-
-	/** The name of the file that will be the created truststore. */
-	public static final String TRUSTSTORE_FILE = "t2truststore.ubr";
-
-	/**
-	 * The name of the file that contains the password to unlock the keystore
-	 * and truststore.
-	 */
-	public static final String PASSWORD_FILE = "password.txt";
-
-	// --------- UNUSED ---------
-	// /**
-	// * The name of the file that contains the mapping from URIs to keystore
-	// * aliases.
-	// */
-	// public static final String URI_ALIAS_MAP = "urlmap.txt";
-
-	/**
-	 * Used to instruct the Taverna credential manager to use a non-default
-	 * location for user credentials.
-	 */
-	public static final String CREDENTIAL_MANAGER_DIRECTORY = "-cmdir";
-
-	/**
-	 * Used to instruct the Taverna credential manager to take its master
-	 * password from standard input.
-	 */
-	public static final String CREDENTIAL_MANAGER_PASSWORD = "-cmpassword";
-
-	/**
-	 * Name of environment variable used to pass HELIO security tokens to
-	 * workflows.
-	 */
-	// This technique is known to be insecure; bite me.
-	public static final String HELIO_TOKEN_NAME = "HELIO_CIS_TOKEN";
-
-	/**
-	 * The name of the standard listener, which is installed by default.
-	 */
-	public static final String DEFAULT_LISTENER_NAME = "io";
-
-	/**
-	 * Time to wait for the subprocess to wait, in milliseconds.
-	 */
-	public static final int START_WAIT_TIME = 1500;
-
-	/**
-	 * Time to wait for success or failure of a death-causing activity (i.e.,
-	 * sending a signal).
-	 */
-	public static final int DEATH_TIME = 333;
-
-	/**
-	 * The name of the file (in this code's resources) that provides the default
-	 * security policy that we use.
-	 */
-	public static final String SECURITY_POLICY_FILE = "security.policy";
-
-	/**
-	 * The Java property holding security policy info.
-	 */
-	public static final String SEC_POLICY_PROP = "java.security.policy";
-	/**
-	 * The Java property to set to make this code not try to enforce security
-	 * policy.
-	 */
-	public static final String UNSECURE_PROP = "taverna.suppressrestrictions.rmi";
-	/**
-	 * The Java property that holds the name of the host name to enforce.
-	 */
-	public static final String RMI_HOST_PROP = "java.rmi.server.hostname";
-	/**
-	 * The default hostname to require in secure mode. This is the
-	 * <i>resolved</i> version of "localhost".
-	 */
-	public static final String LOCALHOST;
-	static {
-		String h = "127.0.0.1"; // fallback
-		try {
-			h = InetAddress.getByName("localhost").getHostAddress();
-		} catch (UnknownHostException e) {
-			e.printStackTrace();
-		} finally {
-			LOCALHOST = h;
-		}
-	}
-
-	/**
-	 * Time to wait during closing down this process. In milliseconds.
-	 */
-	public static final int DEATH_DELAY = 500;
-	/**
-	 * The name of the property describing where shared directories should be
-	 * located.
-	 */
-	public static final String SHARED_DIR_PROP = "taverna.sharedDirectory";
-
-	public static final String TIME = "/usr/bin/time";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
deleted file mode 100644
index dd18db0..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.api;
-/*
- * 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.
- */
-
-/**
- * 
- * @author Donal Fellows
- */
-public interface RunAccounting {
-	/**
-	 * Logs that a run has started executing.
-	 */
-	void runStarted();
-
-	/**
-	 * Logs that a run has finished executing.
-	 */
-	void runCeased();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
deleted file mode 100644
index 52c7009..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.api;
-/*
- * 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.
- */
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-
-import org.taverna.server.localworker.impl.LocalWorker;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-
-/**
- * The interface between the connectivity layer and the thunk to the
- * subprocesses.
- * 
- * @author Donal Fellows
- */
-public interface Worker {
-	/**
-	 * Fire up the workflow. This causes a transition into the operating state.
-	 * 
-	 * @param local
-	 *            The reference to the factory class for this worker.
-	 * @param executeWorkflowCommand
-	 *            The command to run to execute the workflow.
-	 * @param workflow
-	 *            The workflow document to execute.
-	 * @param workingDir
-	 *            What directory to use as the working directory.
-	 * @param inputBaclavaFile
-	 *            The baclava file to use for inputs, or <tt>null</tt> to use
-	 *            the other <b>input*</b> arguments' values.
-	 * @param inputRealFiles
-	 *            A mapping of input names to files that supply them. Note that
-	 *            we assume that nothing mapped here will be mapped in
-	 *            <b>inputValues</b>.
-	 * @param inputValues
-	 *            A mapping of input names to values to supply to them. Note
-	 *            that we assume that nothing mapped here will be mapped in
-	 *            <b>inputFiles</b>.
-	 * @param inputDelimiters
-	 *            A mapping of input names to characters used to split them into
-	 *            lists.
-	 * @param outputBaclavaFile
-	 *            What baclava file to write the output from the workflow into,
-	 *            or <tt>null</tt> to have it written into the <tt>out</tt>
-	 *            subdirectory.
-	 * @param contextDirectory
-	 *            The directory containing the keystore and truststore. <i>Must
-	 *            not be <tt>null</tt>.</i>
-	 * @param keystorePassword
-	 *            The password to the keystore and truststore. <i>Must not be
-	 *            <tt>null</tt>.</i>
-	 * @param generateProvenance
-	 *            Whether to generate a run bundle containing provenance data.
-	 * @param environment
-	 *            Any environment variables that need to be added to the
-	 *            invokation.
-	 * @param masterToken
-	 *            The internal name of the workflow run.
-	 * @param runtimeSettings
-	 *            List of configuration details for the forked runtime.
-	 * @return Whether a successful start happened.
-	 * @throws Exception
-	 *             If any of quite a large number of things goes wrong.
-	 */
-	boolean initWorker(LocalWorker local, String executeWorkflowCommand,
-			byte[] workflow, File workingDir, File inputBaclavaFile,
-			Map<String, File> inputRealFiles, Map<String, String> inputValues,
-			Map<String, String> inputDelimiters, File outputBaclavaFile,
-			File contextDirectory, char[] keystorePassword,
-			boolean generateProvenance, Map<String, String> environment,
-			String masterToken, List<String> runtimeSettings) throws Exception;
-
-	/**
-	 * Kills off the subprocess if it exists and is alive.
-	 * 
-	 * @throws Exception
-	 *             if anything goes badly wrong when the worker is being killed
-	 *             off.
-	 */
-	void killWorker() throws Exception;
-
-	/**
-	 * Move the worker out of the stopped state and back to operating.
-	 * 
-	 * @throws Exception
-	 *             if it fails (which it always does; operation currently
-	 *             unsupported).
-	 */
-	void startWorker() throws Exception;
-
-	/**
-	 * Move the worker into the stopped state from the operating state.
-	 * 
-	 * @throws Exception
-	 *             if it fails (which it always does; operation currently
-	 *             unsupported).
-	 */
-	void stopWorker() throws Exception;
-
-	/**
-	 * @return The status of the workflow run. Note that this can be an
-	 *         expensive operation.
-	 */
-	RemoteStatus getWorkerStatus();
-
-	/**
-	 * @return The listener that is registered by default, in addition to all
-	 *         those that are explicitly registered by the user.
-	 */
-	RemoteListener getDefaultListener();
-
-	/**
-	 * @param receiver
-	 *            The destination where any final usage records are to be
-	 *            written in order to log them back to the server.
-	 */
-	void setURReceiver(UsageRecordReceiver receiver);
-
-	/**
-	 * Arrange for the deletion of any resources created during worker process
-	 * construction. Guaranteed to be the last thing done before finalization.
-	 * 
-	 * @throws ImplementationException
-	 *             If anything goes wrong.
-	 */
-	void deleteLocalResources() throws ImplementationException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
deleted file mode 100644
index 0fd2d20..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.taverna.server.localworker.api;
-/*
- * 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.
- */
-
-
-/**
- * Class that manufactures instances of {@link Worker}.
- * 
- * @author Donal Fellows
- */
-public interface WorkerFactory {
-	/**
-	 * Create an instance of the low-level worker class.
-	 * 
-	 * @return The worker object.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	Worker makeInstance() throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
deleted file mode 100644
index 6b7ba77..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.impl;
-/*
- * 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.
- */
-
-import static org.apache.commons.io.FileUtils.forceDelete;
-import static org.apache.commons.io.FileUtils.forceMkdir;
-import static org.apache.commons.io.FileUtils.touch;
-import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedNewFile;
-
-import java.io.File;
-import java.io.IOException;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-
-import org.apache.commons.collections.MapIterator;
-import org.apache.commons.collections.map.ReferenceMap;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
-import org.taverna.server.localworker.remote.RemoteFile;
-
-/**
- * This class acts as a remote-aware delegate for the workflow run's working
- * directory and its subdirectories.
- * 
- * @author Donal Fellows
- * @see FileDelegate
- */
-@SuppressWarnings("serial")
-public class DirectoryDelegate extends UnicastRemoteObject implements
-		RemoteDirectory {
-	private File dir;
-	private DirectoryDelegate parent;
-	private ReferenceMap localCache;
-
-	/**
-	 * @param dir
-	 * @param parent
-	 * @throws RemoteException
-	 *             If registration of the directory fails.
-	 */
-	public DirectoryDelegate(@Nonnull File dir,
-			@Nonnull DirectoryDelegate parent) throws RemoteException {
-		super();
-		this.localCache = new ReferenceMap();
-		this.dir = dir;
-		this.parent = parent;
-	}
-
-	@Override
-	public Collection<RemoteDirectoryEntry> getContents()
-			throws RemoteException {
-		List<RemoteDirectoryEntry> result = new ArrayList<>();
-		for (String s : dir.list()) {
-			if (s.equals(".") || s.equals(".."))
-				continue;
-			File f = new File(dir, s);
-			RemoteDirectoryEntry entry;
-			synchronized (localCache) {
-				entry = (RemoteDirectoryEntry) localCache.get(s);
-				if (f.isDirectory()) {
-					if (entry == null || !(entry instanceof DirectoryDelegate)) {
-						entry = new DirectoryDelegate(f, this);
-						localCache.put(s, entry);
-					}
-				} else if (f.isFile()) {
-					if (entry == null || !(entry instanceof FileDelegate)) {
-						entry = new FileDelegate(f, this);
-						localCache.put(s, entry);
-					}
-				} else {
-					// not file or dir; skip...
-					continue;
-				}
-			}
-			result.add(entry);
-		}
-		return result;
-	}
-
-	@Override
-	public RemoteFile makeEmptyFile(String name) throws IOException {
-		File f = getValidatedNewFile(dir, name);
-		touch(f);
-		FileDelegate delegate = new FileDelegate(f, this);
-		synchronized (localCache) {
-			localCache.put(name, delegate);
-		}
-		return delegate;
-	}
-
-	@Override
-	public RemoteDirectory makeSubdirectory(String name) throws IOException {
-		File f = getValidatedNewFile(dir, name);
-		forceMkdir(f);
-		DirectoryDelegate delegate = new DirectoryDelegate(f, this);
-		synchronized (localCache) {
-			localCache.put(name, delegate);
-		}
-		return delegate;
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public void destroy() throws IOException {
-		if (parent == null)
-			throw new IOException("tried to destroy main job working directory");
-		Collection<RemoteDirectoryEntry> values;
-		synchronized (localCache) {
-			values = new ArrayList<>(localCache.values());
-		}
-		for (RemoteDirectoryEntry obj : values) {
-			if (obj == null)
-				continue;
-			try {
-				obj.destroy();
-			} catch (IOException e) {
-			}
-		}
-		forceDelete(dir);
-		parent.forgetEntry(this);
-	}
-
-	@Override
-	public RemoteDirectory getContainingDirectory() {
-		return parent;
-	}
-
-	void forgetEntry(@Nonnull RemoteDirectoryEntry entry) {
-		synchronized (localCache) {
-			MapIterator i = localCache.mapIterator();
-			while (i.hasNext()) {
-				Object key = i.next();
-				if (entry == i.getValue()) {
-					localCache.remove(key);
-					break;
-				}
-			}
-		}
-	}
-
-	@Override
-	public String getName() {
-		if (parent == null)
-			return "";
-		return dir.getName();
-	}
-
-	@Override
-	public Date getModificationDate() throws RemoteException {
-		return new Date(dir.lastModified());
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
deleted file mode 100644
index 8dd9ede..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.impl;
-/*
- * 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.
- */
-
-import static java.lang.System.arraycopy;
-import static java.net.InetAddress.getLocalHost;
-import static org.apache.commons.io.FileUtils.copyFile;
-import static org.apache.commons.io.FileUtils.forceDelete;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.UnknownHostException;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.Date;
-
-import javax.annotation.Nonnull;
-
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteFile;
-
-/**
- * This class acts as a remote-aware delegate for the files in a workflow run's
- * working directory and its subdirectories.
- * 
- * @author Donal Fellows
- * @see DirectoryDelegate
- */
-@java.lang.SuppressWarnings("serial")
-public class FileDelegate extends UnicastRemoteObject implements RemoteFile {
-	private File file;
-	private DirectoryDelegate parent;
-
-	/**
-	 * @param file
-	 * @param parent
-	 * @throws RemoteException
-	 *             If registration of the file fails.
-	 */
-	public FileDelegate(@Nonnull File file, @Nonnull DirectoryDelegate parent)
-			throws RemoteException {
-		super();
-		this.file = file;
-		this.parent = parent;
-	}
-
-	@Override
-	public byte[] getContents(int offset, int length) throws IOException {
-		if (length == -1)
-			length = (int) (file.length() - offset);
-		if (length < 0 || length > 1024 * 64)
-			length = 1024 * 64;
-		byte[] buffer = new byte[length];
-		int read;
-		try (FileInputStream fis = new FileInputStream(file)) {
-			if (offset > 0 && fis.skip(offset) != offset)
-				throw new IOException("did not move to correct offset in file");
-			read = fis.read(buffer);
-		}
-		if (read <= 0)
-			return new byte[0];
-		if (read < buffer.length) {
-			byte[] shortened = new byte[read];
-			arraycopy(buffer, 0, shortened, 0, read);
-			return shortened;
-		}
-		return buffer;
-	}
-
-	@Override
-	public long getSize() {
-		return file.length();
-	}
-
-	@Override
-	public void setContents(byte[] data) throws IOException {
-		try (FileOutputStream fos = new FileOutputStream(file)) {
-			fos.write(data);
-		}
-	}
-
-	@Override
-	public void appendContents(byte[] data) throws IOException {
-		try (FileOutputStream fos = new FileOutputStream(file, true)) {
-			fos.write(data);
-		}
-	}
-
-	@Override
-	public void destroy() throws IOException {
-		forceDelete(file);
-		parent.forgetEntry(this);
-		parent = null;
-	}
-
-	@Override
-	public RemoteDirectory getContainingDirectory() {
-		return parent;
-	}
-
-	@Override
-	public String getName() {
-		return file.getName();
-	}
-
-	@Override
-	public void copy(RemoteFile sourceFile) throws RemoteException, IOException {
-		String sourceHost = sourceFile.getNativeHost();
-		if (!getNativeHost().equals(sourceHost)) {
-			throw new IOException(
-					"cross-system copy not implemented; cannot copy from "
-							+ sourceHost + " to " + getNativeHost());
-		}
-		// Must copy; cannot count on other file to stay unmodified
-		copyFile(new File(sourceFile.getNativeName()), file);
-	}
-
-	@Override
-	public String getNativeName() {
-		return file.getAbsolutePath();
-	}
-
-	@Override
-	public String getNativeHost() {
-		try {
-			return getLocalHost().getHostAddress();
-		} catch (UnknownHostException e) {
-			throw new RuntimeException(
-					"unexpected failure to resolve local host address", e);
-		}
-	}
-
-	@Override
-	public Date getModificationDate() throws RemoteException {
-		return new Date(file.lastModified());
-	}
-}


[37/42] incubator-taverna-server git commit: package org.apache.taverna.server.*

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/webapp/WEB-INF/beans.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/beans.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/beans.xml
index f0fc89c..4be9468 100644
--- a/taverna-server-webapp/src/main/webapp/WEB-INF/beans.xml
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/beans.xml
@@ -24,7 +24,7 @@ limitations under the License.
 		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
 		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
-	<bean id="webapp" class="org.taverna.server.master.TavernaServer">
+	<bean id="webapp" class="org.apache.taverna.server.master.TavernaServer">
 		<property name="policy" ref="worker.policy" />
 		<property name="runStore" ref="worker.rundb" />
 		<property name="fileUtils" ref="fileUtils" />
@@ -37,7 +37,7 @@ limitations under the License.
 		<lookup-method name="getPolicyDescription" bean="webapp.policyView" />
 	</bean>
 
-	<bean id="webapp.support" class="org.taverna.server.master.TavernaServerSupport">
+	<bean id="webapp.support" class="org.apache.taverna.server.master.TavernaServerSupport">
 		<property name="policy" ref="worker.policy" />
 		<property name="listenerFactory" ref="localworker.factory" />
 		<property name="runFactory" ref="localworker.factory" />
@@ -57,21 +57,21 @@ limitations under the License.
 		<property name="capabilitySource" ref="capabilities" />
 	</bean>
 
-	<bean id="capabilities" class="org.taverna.server.master.utils.CapabilityLister" />
+	<bean id="capabilities" class="org.apache.taverna.server.master.utils.CapabilityLister" />
 
-	<bean id="webapp.policyView" class="org.taverna.server.master.PolicyREST">
+	<bean id="webapp.policyView" class="org.apache.taverna.server.master.PolicyREST">
 		<property name="support" ref="webapp.support" />
 		<property name="policy" ref="worker.policy" />
 		<property name="listenerFactory" ref="localworker.factory" />
 		<property name="notificationEngine" ref="notificationFabric" />
 	</bean>
 
-	<bean id="contentsDescriptorBuilder" class="org.taverna.server.master.ContentsDescriptorBuilder">
+	<bean id="contentsDescriptorBuilder" class="org.apache.taverna.server.master.ContentsDescriptorBuilder">
 		<property name="uriBuilderFactory" ref="webapp" />
 		<property name="fileUtils" ref="fileUtils" />
 	</bean>
 
-	<bean id="webapp.state" class="org.taverna.server.master.ManagementState">
+	<bean id="webapp.state" class="org.apache.taverna.server.master.ManagementState">
 		<description>The initial state of the webapp.</description>
 		<property name="logIncomingWorkflows" value="${default.logworkflows}" />
 		<property name="allowNewWorkflowRuns" value="${default.permitsubmit}" />
@@ -80,13 +80,13 @@ limitations under the License.
 		<property name="self" ref="webapp.state" />
 	</bean>
 
-	<bean id="webapp.invocationCounter" class="org.taverna.server.master.utils.InvocationCounter" />
-	<bean id="webapp.perfLogger" class="org.taverna.server.master.utils.CallTimeLogger">
+	<bean id="webapp.invocationCounter" class="org.apache.taverna.server.master.utils.InvocationCounter" />
+	<bean id="webapp.perfLogger" class="org.apache.taverna.server.master.utils.CallTimeLogger">
 		<property name="threshold" value="${calltime.logthreshold:4000000}" />
 	</bean>
 
 	<bean id="run.coreView.prototype" scope="prototype"
-		class="org.taverna.server.master.RunREST">
+		class="org.apache.taverna.server.master.RunREST">
 		<property name="support" ref="webapp.support" />
 		<property name="cdBuilder" ref="contentsDescriptorBuilder" />
 		<lookup-method name="makeSecurityInterface" bean="run.securityView.prototype" />
@@ -97,52 +97,52 @@ limitations under the License.
 	</bean>
 
 	<bean id="run.directoryView.prototype" scope="prototype"
-		class="org.taverna.server.master.DirectoryREST">
+		class="org.apache.taverna.server.master.DirectoryREST">
 		<property name="support" ref="webapp.support" />
 		<property name="fileUtils" ref="fileUtils" />
 	</bean>
 
 	<bean id="run.listenersView.prototype" scope="prototype"
-		class="org.taverna.server.master.ListenersREST">
+		class="org.apache.taverna.server.master.ListenersREST">
 		<property name="support" ref="webapp.support" />
 		<lookup-method name="makeListenerInterface" bean="run.singleListenerView.prototype" />
 	</bean>
 
 	<bean id="run.singleListenerView.prototype" scope="prototype"
-		class="org.taverna.server.master.SingleListenerREST">
+		class="org.apache.taverna.server.master.SingleListenerREST">
 		<lookup-method name="makePropertyInterface" bean="run.propertyView.prototype" />
 	</bean>
 
 	<bean id="run.propertyView.prototype" scope="prototype"
-		class="org.taverna.server.master.ListenerPropertyREST">
+		class="org.apache.taverna.server.master.ListenerPropertyREST">
 		<property name="support" ref="webapp.support" />
 	</bean>
 
 	<bean id="run.inputView.prototype" scope="prototype"
-		class="org.taverna.server.master.InputREST">
+		class="org.apache.taverna.server.master.InputREST">
 		<property name="support" ref="webapp.support" />
 		<property name="cdBuilder" ref="contentsDescriptorBuilder" />
 		<property name="fileUtils" ref="fileUtils" />
 	</bean>
 
 	<bean id="run.securityView.prototype" scope="prototype"
-		class="org.taverna.server.master.RunSecurityREST">
+		class="org.apache.taverna.server.master.RunSecurityREST">
 		<property name="support" ref="webapp.support" />
 	</bean>
 
 	<bean id="run.interactionFeed.prototype" scope="prototype"
-		class="org.taverna.server.master.InteractionFeed">
+		class="org.apache.taverna.server.master.InteractionFeed">
 		<property name="interactionFeedSupport" ref="interactionFeed" />
 	</bean>
 
-	<bean id="feed" class="org.taverna.server.master.notification.atom.AtomFeed">
+	<bean id="feed" class="org.apache.taverna.server.master.notification.atom.AtomFeed">
 		<property name="eventSource" ref="dispatch.atom" />
 		<property name="support" ref="webapp.support" />
 		<property name="feedLanguage" value="${atom.language}" />
 		<property name="abdera" ref="abdera" />
 	</bean>
 
-	<bean id="admin" class="org.taverna.server.master.admin.AdminBean">
+	<bean id="admin" class="org.apache.taverna.server.master.admin.AdminBean">
 		<property name="adminHtmlFile" value="/admin.html" />
 		<property name="counter" ref="webapp.invocationCounter" />
 		<property name="factory" ref="localworker.factory" />
@@ -153,23 +153,23 @@ limitations under the License.
 		<property name="userStore" ref="userStore" />
 	</bean>
 
-	<bean id="IdentityMapper" class="org.taverna.server.master.identity.CompositeIDMapper">
+	<bean id="IdentityMapper" class="org.apache.taverna.server.master.identity.CompositeIDMapper">
 		<property name="identityMappers">
 			<list>
 				<bean id="AuthorityBased"
-					class="org.taverna.server.master.identity.AuthorityDerivedIDMapper">
+					class="org.apache.taverna.server.master.identity.AuthorityDerivedIDMapper">
 					<description>Derives the local user identity to use for execution
 						from the LOCALUSER_* Spring Security authority. Thus, if the user
 						has &quot;LOCALUSER_foo&quot;, they will be executing as the local
 						user id &quot;foo&quot;.</description>
 				</bean>
 				<bean id="SelfAccess"
-					class="org.taverna.server.master.identity.WorkflowInternalAuthProvider.WorkflowSelfIDMapper">
+					class="org.apache.taverna.server.master.identity.WorkflowInternalAuthProvider.WorkflowSelfIDMapper">
 					<description>Handles the case where a workflow is accessing itself for
 						the purpose of publishing interactions.</description>
 					<property name="runStore" ref="worker.rundb" />
 				</bean>
-				<bean id="Extracting" class="org.taverna.server.master.identity.NameIDMapper">
+				<bean id="Extracting" class="org.apache.taverna.server.master.identity.NameIDMapper">
 					<description>An alternate mechanism for mapping users. This tries
 						to use an RE to extract the user name from the principal name.
 					</description>
@@ -180,7 +180,7 @@ limitations under the License.
 						</description>
 					</property>
 				</bean>
-				<bean id="Constant" class="org.taverna.server.master.identity.ConstantIDMapper">
+				<bean id="Constant" class="org.apache.taverna.server.master.identity.ConstantIDMapper">
 					<description>How to map web principals to local users. This one
 						maps everyone to the same user, "taverna".
 					</description>
@@ -192,7 +192,7 @@ limitations under the License.
 
 	<bean id="passwordEncoder"
 		class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
-	<bean class="org.taverna.server.master.identity.UserStore" id="userStore">
+	<bean class="org.apache.taverna.server.master.identity.UserStore" id="userStore">
 		<property name="persistenceManagerBuilder" ref="pmb" />
 		<property name="baselineUserProperties">
 			<util:properties location="/WEB-INF/security/users.properties" />
@@ -206,7 +206,7 @@ limitations under the License.
 		<props> <prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop> 
 		<prop key="hibernate.hbm2ddl.auto">create</prop> </props> </property> <property 
 		name="annotatedClasses"> <list> </list> </property> </bean> -->
-	<bean id="pmb" class="org.taverna.server.master.utils.JDOSupport.PersistenceManagerBuilder">
+	<bean id="pmb" class="org.apache.taverna.server.master.utils.JDOSupport.PersistenceManagerBuilder">
 		<property name="persistenceManagerFactory">
 			<bean id="pmf" class="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"
 				destroy-method="close">
@@ -224,14 +224,14 @@ limitations under the License.
 						<prop key="datanucleus.autoCreateSchema">true</prop>
 						<prop key="datanucleus.PersistenceUnitName">TavernaServer</prop>
 						<prop key="datanucleus.rdbms.datastoreAdapterClassName"
-							>org.taverna.server.master.utils.LoggingDerbyAdapter</prop>
+							>org.apache.taverna.server.master.utils.LoggingDerbyAdapter</prop>
 					</props>
 				</property>
 			</bean>
 		</property>
 	</bean>
 	<bean id="transactionAspect"
-		class="org.taverna.server.master.utils.JDOSupport.TransactionAspect" />
+		class="org.apache.taverna.server.master.utils.JDOSupport.TransactionAspect" />
 
 	<bean id="systemPrereqs" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
 		<description>http://stackoverflow.com/questions/3339736/set-system-property-with-spring-configuration-file</description>
@@ -239,14 +239,14 @@ limitations under the License.
 		<property name="targetMethod" value="putAll" />
 		<property name="arguments">
 			<util:properties>
-				<prop key="derby.stream.error.field">org.taverna.server.master.utils.DerbyUtils.TO_LOG</prop>
+				<prop key="derby.stream.error.field">org.apache.taverna.server.master.utils.DerbyUtils.TO_LOG</prop>
 				<prop key="derby.stream.error.logSeverityLevel">30000</prop>
 			</util:properties>
 		</property>
 	</bean>
 	<!-- TODO: control the location of the database properly, or move to JNDI 
 		TODO: review whether what we are doing now is correct! -->
-	<bean id="dataSource" class="org.taverna.server.master.utils.WebappAwareDataSource">
+	<bean id="dataSource" class="org.apache.taverna.server.master.utils.WebappAwareDataSource">
 		<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
 		<property name="url"
 			value="jdbc:derby:directory:%{WEBAPPROOT}tavernaserver;create=true" />
@@ -258,9 +258,9 @@ limitations under the License.
 		<property name="contextualizer" ref="contextualizer" />
 	</bean>
 
-	<bean id="contextualizer" class="org.taverna.server.master.utils.Contextualizer" />
+	<bean id="contextualizer" class="org.apache.taverna.server.master.utils.Contextualizer" />
 
-	<bean id="usageRecordSink" class="org.taverna.server.master.usage.UsageRecordRecorder">
+	<bean id="usageRecordSink" class="org.apache.taverna.server.master.usage.UsageRecordRecorder">
 		<property name="state" ref="webapp.state" />
 		<property name="contextualizer" ref="contextualizer" />
 		<property name="persistenceManagerBuilder" ref="pmb" />
@@ -272,10 +272,10 @@ limitations under the License.
 	<context:property-placeholder
 		ignore-unresolvable="true" order="2" properties-ref="default-factory-properties" />
 	<util:properties id="default-factory-properties">
-		<prop key="backEndFactory">org.taverna.server.master.localworker.IdAwareForkRunFactory</prop>
+		<prop key="backEndFactory">org.apache.taverna.server.master.localworker.IdAwareForkRunFactory</prop>
 	</util:properties>
 
-	<!-- This bean configuration replaced with org.taverna.server.master.localworker.LocalWorkerFactory -->
+	<!-- This bean configuration replaced with org.apache.taverna.server.master.localworker.LocalWorkerFactory -->
 	<!-- <bean id="localworker.factory" scope="singleton" lazy-init="false" 
 		class="${backEndFactory}"> <description> The simple policy manager and factory 
 		for the baseline localworker case. </description> <property name="state" 
@@ -290,7 +290,7 @@ limitations under the License.
 	<!-- <task:executor id="URThreads" pool-size="${pool.size}" /> -->
 
 	<bean id="worker.securityContext"
-		class="org.taverna.server.master.worker.SecurityContextFactory">
+		class="org.apache.taverna.server.master.worker.SecurityContextFactory">
 		<property name="runDatabase" ref="worker.rundb" />
 		<property name="filenameConverter" ref="fileUtils" />
 		<property name="x500Utils" ref="x500Utils" />
@@ -300,15 +300,15 @@ limitations under the License.
 		<property name="passwordIssuer" ref="passwordIssuer" />
 	</bean>
 
-	<bean id="passwordIssuer" class="org.taverna.server.master.worker.PasswordIssuer">
+	<bean id="passwordIssuer" class="org.apache.taverna.server.master.worker.PasswordIssuer">
 		<!-- <property name="length" value="8" /> -->
 	</bean>
 
-	<bean id="certificateChainFetcher" class="org.taverna.server.master.utils.CertificateChainFetcher">
+	<bean id="certificateChainFetcher" class="org.apache.taverna.server.master.utils.CertificateChainFetcher">
 		<property name="secure" value="${fetchCertificateChain}" />
 	</bean>
 
-	<bean id="localworker.state" class="org.taverna.server.master.localworker.LocalWorkerState"
+	<bean id="localworker.state" class="org.apache.taverna.server.master.localworker.LocalWorkerState"
 		scope="singleton" lazy-init="false">
 		<description>
 			The state of the simple factory for the identity-aware
@@ -358,7 +358,7 @@ limitations under the License.
 		<property name="defaultExecuteWorkflowScript" value="${executeWorkflowScript:NONE}" />
 	</bean>
 
-	<bean id="worker.policy" class="org.taverna.server.master.worker.PolicyImpl">
+	<bean id="worker.policy" class="org.apache.taverna.server.master.worker.PolicyImpl">
 		<description>
 			The implementation of the access control policy supported
 			by the localworker run engine.
@@ -366,7 +366,7 @@ limitations under the License.
 		<property name="limits" ref="localworker.state" />
 		<property name="runDB" ref="worker.rundb" />
 	</bean>
-	<bean id="worker.rundb" class="org.taverna.server.master.worker.RunDatabase">
+	<bean id="worker.rundb" class="org.apache.taverna.server.master.worker.RunDatabase">
 		<property name="notifier" ref="worker.notifier" />
 		<property name="typeNotifiers">
 			<list>
@@ -380,28 +380,28 @@ limitations under the License.
 		<property name="dao" ref="worker.runDAO" />
 	</bean>
 	<bean id="cn.email"
-		class="org.taverna.server.master.worker.VelocityCompletionNotifier">
+		class="org.apache.taverna.server.master.worker.VelocityCompletionNotifier">
 		<property name="name" value="email" />
 		<property name="subject" value="Workflow run finished executing" />
 		<property name="velocityEngine" ref="velocity" />
 		<property name="uriBuilderFactory" ref="webapp" />
 	</bean>
 	<bean id="cn.sms"
-		class="org.taverna.server.master.worker.VelocityCompletionNotifier">
+		class="org.apache.taverna.server.master.worker.VelocityCompletionNotifier">
 		<property name="name" value="sms" />
 		<property name="subject" value="Run finished" />
 		<property name="velocityEngine" ref="velocity" />
 		<property name="uriBuilderFactory" ref="webapp" />
 	</bean>
 	<bean id="cn.twitter"
-		class="org.taverna.server.master.worker.VelocityCompletionNotifier">
+		class="org.apache.taverna.server.master.worker.VelocityCompletionNotifier">
 		<property name="name" value="twitter" />
 		<property name="subject" value="Run finished" />
 		<property name="velocityEngine" ref="velocity" />
 		<property name="uriBuilderFactory" ref="webapp" />
 	</bean>
 	
-	<bean id="worker.runDAO" class="org.taverna.server.master.worker.RunDatabaseDAO">
+	<bean id="worker.runDAO" class="org.apache.taverna.server.master.worker.RunDatabaseDAO">
 		<description>
 			The implementation of the catalog of workflow runs
 			supported by the localworker run engine.
@@ -419,7 +419,7 @@ limitations under the License.
 	</task:scheduled-tasks>
 
 	<bean id="notificationFabric"
-		class="org.taverna.server.master.notification.NotificationEngine">
+		class="org.apache.taverna.server.master.notification.NotificationEngine">
 		<property name="dispatchers">
 			<list>
 				<ref bean="dispatch.email" />
@@ -435,7 +435,7 @@ limitations under the License.
 		</property>
 	</bean>
 
-	<bean id="dispatch.email" class="org.taverna.server.master.notification.EmailDispatcher">
+	<bean id="dispatch.email" class="org.apache.taverna.server.master.notification.EmailDispatcher">
 		<property name="from" value="${email.from}" />
 		<property name="messageContentType" value="${email.type}" />
 		<property name="cooldownSeconds" value="${message.cooldown}" />
@@ -448,18 +448,18 @@ limitations under the License.
 		</property>
 	</bean>
 	<bean id="dispatch.twitter"
-		class="org.taverna.server.master.notification.TwitterDispatcher">
+		class="org.apache.taverna.server.master.notification.TwitterDispatcher">
 		<property name="cooldownSeconds" value="${message.cooldown}" />
 		<property name="accessToken" value="${twitter.oauth.accessToken}" />
 		<property name="accessSecret" value="${twitter.oauth.accessTokenSecret}" />
 	</bean>
-	<bean id="dispatch.xmpp" class="org.taverna.server.master.notification.JabberDispatcher">
+	<bean id="dispatch.xmpp" class="org.apache.taverna.server.master.notification.JabberDispatcher">
 		<property name="resource" value="${xmpp.resource}" />
 		<property name="host" value="${xmpp.service}" />
 		<property name="username" value="${xmpp.user}" />
 		<property name="password" value="${xmpp.password}" />
 	</bean>
-	<bean id="dispatch.sms" class="org.taverna.server.master.notification.SMSDispatcher">
+	<bean id="dispatch.sms" class="org.apache.taverna.server.master.notification.SMSDispatcher">
 		<property name="usernameField" value="${sms.userfield}" />
 		<property name="passwordField" value="${sms.passfield}" />
 		<property name="destinationField" value="${sms.destfield}" />
@@ -467,7 +467,7 @@ limitations under the License.
 		<property name="cooldownSeconds" value="${message.cooldown}" />
 	</bean>
 
-	<bean id="dispatch.atom" class="org.taverna.server.master.notification.atom.EventDAO">
+	<bean id="dispatch.atom" class="org.apache.taverna.server.master.notification.atom.EventDAO">
 		<property name="expiryAgeDays" value="${atom.lifespan}" />
 		<property name="persistenceManagerBuilder" ref="pmb" />
 		<property name="uriBuilderFactory" ref="feed" />
@@ -475,42 +475,42 @@ limitations under the License.
 	</bean>
 
 	<bean id="worker.notifier"
-		class="org.taverna.server.master.worker.SimpleFormattedCompletionNotifier">
+		class="org.apache.taverna.server.master.worker.SimpleFormattedCompletionNotifier">
 		<property name="subject" value="${message.termination.subject}" />
 		<property name="messageFormat" value="${message.termination.body}" />
 		<property name="name" value="fallback"/>
 	</bean>
 
-	<bean id="fileUtils" class="org.taverna.server.master.utils.FilenameUtils" />
-	<bean id="x500Utils" class="org.taverna.server.master.utils.X500Utils" />
+	<bean id="fileUtils" class="org.apache.taverna.server.master.utils.FilenameUtils" />
+	<bean id="x500Utils" class="org.apache.taverna.server.master.utils.X500Utils" />
 	<task:scheduler id="taskScheduler" pool-size="${pool.size}" />
 
-	<bean class="org.taverna.server.master.utils.JCECheck" id="JCECheck" />
+	<bean class="org.apache.taverna.server.master.utils.JCECheck" id="JCECheck" />
 
-	<bean class="org.taverna.server.master.interaction.InteractionFeedSupport"
+	<bean class="org.apache.taverna.server.master.interaction.InteractionFeedSupport"
 		id="interactionFeed" scope="singleton">
 		<property name="abdera" ref="abdera" />
 		<property name="support" ref="webapp.support" />
 		<property name="uriBuilder" ref="webapp" />
 		<property name="utils" ref="fileUtils" />
 	</bean>
-	<bean class="org.taverna.server.master.rest.handler.FeedHandler" id="atomFeedHandler">
+	<bean class="org.apache.taverna.server.master.rest.handler.FeedHandler" id="atomFeedHandler">
 		<property name="abdera" ref="abdera" />
 	</bean>
-	<bean class="org.taverna.server.master.rest.handler.EntryHandler" id="atomEntryHandler">
+	<bean class="org.apache.taverna.server.master.rest.handler.EntryHandler" id="atomEntryHandler">
 		<property name="abdera" ref="abdera" />
 	</bean>
 
-	<bean id="authProvider" class="org.taverna.server.master.identity.StrippedDownAuthProvider">
+	<bean id="authProvider" class="org.apache.taverna.server.master.identity.StrippedDownAuthProvider">
 		<property name="passwordEncoder" ref="passwordEncoder" />
 		<property name="userDetailsService">
-			<bean class="org.taverna.server.master.identity.UserStore.CachedUserStore">
+			<bean class="org.apache.taverna.server.master.identity.UserStore.CachedUserStore">
 				<property name="realStore" ref="userStore" />
 			</bean>
 		</property>
 	</bean>
 	<bean id="workflowInternalAuthProvder"
-		class="org.taverna.server.master.identity.WorkflowInternalAuthProvider">
+		class="org.apache.taverna.server.master.identity.WorkflowInternalAuthProvider">
 		<property name="dao" ref="worker.runDAO" />
 		<property name="cacheBound" value="${default.runlimit}" />
 	</bean>
@@ -521,7 +521,7 @@ limitations under the License.
 				<prop key="input.encoding">UTF-8</prop>
 				<prop key="output.encoding">UTF-8</prop>
 				<prop key="runtime.log.logsystem.class">org.apache.velocity.runtime.log.Log4JLogChute</prop>
-				<prop key="runtime.log.logsystem.log4j.logger">org.taverna.server.master.worker.VelocityCompletionNotifier</prop>
+				<prop key="runtime.log.logsystem.log4j.logger">org.apache.taverna.server.master.worker.VelocityCompletionNotifier</prop>
 				<prop key="resource.loader">class</prop>
 				<prop key="class.resource.loader.description">Velocity Classpath Resource Loader</prop>
 				<prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/webapp/WEB-INF/insecure.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/insecure.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/insecure.xml
index b2b18d6..a643801 100644
--- a/taverna-server-webapp/src/main/webapp/WEB-INF/insecure.xml
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/insecure.xml
@@ -36,7 +36,7 @@ limitations under the License.
 	<context:property-placeholder order="0" ignore-unresolvable="true"
 		 properties-ref="security.override.properties" />
 	<util:properties id="security.override.properties">
-		<prop key="backEndFactory">org.taverna.server.master.localworker.ForkRunFactory</prop>
+		<prop key="backEndFactory">org.apache.taverna.server.master.localworker.ForkRunFactory</prop>
 		<prop key="fetchCertificateChain">false</prop>
 		<prop key="suppressRewriteEngine">true</prop>
 		<prop key="requiredChannel">any</prop>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/webapp/WEB-INF/partsecure.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/partsecure.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/partsecure.xml
index ceab286..7e1df05 100644
--- a/taverna-server-webapp/src/main/webapp/WEB-INF/partsecure.xml
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/partsecure.xml
@@ -36,7 +36,7 @@ limitations under the License.
 	<context:property-placeholder order="0" ignore-unresolvable="true"
 		 properties-ref="security.override.properties" />
 	<util:properties id="security.override.properties">
-		<prop key="backEndFactory">org.taverna.server.master.localworker.ForkRunFactory</prop>
+		<prop key="backEndFactory">org.apache.taverna.server.master.localworker.ForkRunFactory</prop>
 		<prop key="fetchCertificateChain">true</prop>
 		<prop key="suppressRewriteEngine">false</prop>
 		<prop key="requiredChannel">https</prop>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/webapp/WEB-INF/providers.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/providers.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/providers.xml
index ffcc053..5ba2a89 100644
--- a/taverna-server-webapp/src/main/webapp/WEB-INF/providers.xml
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/providers.xml
@@ -23,88 +23,88 @@ limitations under the License.
 
 	<import resource="beans.xml" />
 
-	<bean id="ExceptionProvider.BadInputPortName" class="org.taverna.server.master.rest.handler.BadInputPortNameHandler">
+	<bean id="ExceptionProvider.BadInputPortName" class="org.apache.taverna.server.master.rest.handler.BadInputPortNameHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.BadPropertyValue" class="org.taverna.server.master.rest.handler.BadPropertyValueHandler">
+	<bean id="ExceptionProvider.BadPropertyValue" class="org.apache.taverna.server.master.rest.handler.BadPropertyValueHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.BadStateChange" class="org.taverna.server.master.rest.handler.BadStateChangeHandler">
+	<bean id="ExceptionProvider.BadStateChange" class="org.apache.taverna.server.master.rest.handler.BadStateChangeHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.FilesystemAccess" class="org.taverna.server.master.rest.handler.FilesystemAccessHandler">
+	<bean id="ExceptionProvider.FilesystemAccess" class="org.apache.taverna.server.master.rest.handler.FilesystemAccessHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.GeneralFailure" class="org.taverna.server.master.rest.handler.GeneralFailureHandler">
+	<bean id="ExceptionProvider.GeneralFailure" class="org.apache.taverna.server.master.rest.handler.GeneralFailureHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.IllegalArgument" class="org.taverna.server.master.rest.handler.IllegalArgumentHandler">
+	<bean id="ExceptionProvider.IllegalArgument" class="org.apache.taverna.server.master.rest.handler.IllegalArgumentHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
 	<bean id="ExceptionProvider.ImplementationProblem"
-		class="org.taverna.server.master.rest.handler.ImplementationProblemHandler">
+		class="org.apache.taverna.server.master.rest.handler.ImplementationProblemHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.InvalidCredential" class="org.taverna.server.master.rest.handler.InvalidCredentialHandler">
+	<bean id="ExceptionProvider.InvalidCredential" class="org.apache.taverna.server.master.rest.handler.InvalidCredentialHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.NoCreate" class="org.taverna.server.master.rest.handler.NoCreateHandler">
+	<bean id="ExceptionProvider.NoCreate" class="org.apache.taverna.server.master.rest.handler.NoCreateHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.Overloaded" class="org.taverna.server.master.rest.handler.OverloadedHandler">
+	<bean id="ExceptionProvider.Overloaded" class="org.apache.taverna.server.master.rest.handler.OverloadedHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.NoCredential" class="org.taverna.server.master.rest.handler.NoCredentialHandler">
+	<bean id="ExceptionProvider.NoCredential" class="org.apache.taverna.server.master.rest.handler.NoCredentialHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.NoDestroy" class="org.taverna.server.master.rest.handler.NoDestroyHandler">
+	<bean id="ExceptionProvider.NoDestroy" class="org.apache.taverna.server.master.rest.handler.NoDestroyHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.NoDirectoryEntry" class="org.taverna.server.master.rest.handler.NoDirectoryEntryHandler">
+	<bean id="ExceptionProvider.NoDirectoryEntry" class="org.apache.taverna.server.master.rest.handler.NoDirectoryEntryHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.NoListener" class="org.taverna.server.master.rest.handler.NoListenerHandler">
+	<bean id="ExceptionProvider.NoListener" class="org.apache.taverna.server.master.rest.handler.NoListenerHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.NoUpdate" class="org.taverna.server.master.rest.handler.NoUpdateHandler">
+	<bean id="ExceptionProvider.NoUpdate" class="org.apache.taverna.server.master.rest.handler.NoUpdateHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.NotOwner" class="org.taverna.server.master.rest.handler.NotOwnerHandler">
+	<bean id="ExceptionProvider.NotOwner" class="org.apache.taverna.server.master.rest.handler.NotOwnerHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.UnknownRun" class="org.taverna.server.master.rest.handler.UnknownRunHandler">
+	<bean id="ExceptionProvider.UnknownRun" class="org.apache.taverna.server.master.rest.handler.UnknownRunHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.JAXBException" class="org.taverna.server.master.rest.handler.JAXBExceptionHandler">
+	<bean id="ExceptionProvider.JAXBException" class="org.apache.taverna.server.master.rest.handler.JAXBExceptionHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-	<bean id="ExceptionProvider.AccessDenied" class="org.taverna.server.master.rest.handler.AccessDeniedHandler">
+	<bean id="ExceptionProvider.AccessDenied" class="org.apache.taverna.server.master.rest.handler.AccessDeniedHandler">
 		<property name="managementModel" ref="webapp.state" />
 	</bean>
-    <bean id="ExceptionProvider.NegotiationFailed" class="org.taverna.server.master.rest.handler.NegotiationFailedHandler">
+    <bean id="ExceptionProvider.NegotiationFailed" class="org.apache.taverna.server.master.rest.handler.NegotiationFailedHandler">
     </bean>
-	<bean id="MessagingProvider.File" class="org.taverna.server.master.rest.handler.FileMessageHandler">
+	<bean id="MessagingProvider.File" class="org.apache.taverna.server.master.rest.handler.FileMessageHandler">
 		<property name="maxChunkSize" value="${default.messageSize}" />
 	</bean>
-	<bean id="MessagingProvider.FileConcatenation" class="org.taverna.server.master.rest.handler.FileConcatenationHandler">
+	<bean id="MessagingProvider.FileConcatenation" class="org.apache.taverna.server.master.rest.handler.FileConcatenationHandler">
 		<property name="maxChunkSize" value="${default.messageSize}" />
 	</bean>
-	<bean id="MessagingProvider.FileSegment" class="org.taverna.server.master.rest.handler.FileSegmentHandler">
+	<bean id="MessagingProvider.FileSegment" class="org.apache.taverna.server.master.rest.handler.FileSegmentHandler">
 		<property name="maxChunkSize" value="${default.messageSize}" />
 	</bean>
 	<bean id="MessagingProvider.InputStream"
-		class="org.taverna.server.master.rest.handler.InputStreamMessageHandler">
+		class="org.apache.taverna.server.master.rest.handler.InputStreamMessageHandler">
 	</bean>
-	<bean id="MessagingProvider.T2flow" class="org.taverna.server.master.rest.handler.T2FlowDocumentHandler">
+	<bean id="MessagingProvider.T2flow" class="org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler">
 	</bean>
-	<bean id="MessagingProvider.Permission" class="org.taverna.server.master.rest.handler.PermissionHandler">
+	<bean id="MessagingProvider.Permission" class="org.apache.taverna.server.master.rest.handler.PermissionHandler">
 	</bean>
 
-	<bean id="Provider.RuntimeExceptionRemapping" class="org.taverna.server.master.utils.RuntimeExceptionWrapper" />
-	<bean id="MessagingProvider.ZipStream" class="org.taverna.server.master.rest.handler.ZipStreamHandler" />
-	<bean id="MessagingProvider.URIList" class="org.taverna.server.master.rest.handler.URIListHandler" />
+	<bean id="Provider.RuntimeExceptionRemapping" class="org.apache.taverna.server.master.utils.RuntimeExceptionWrapper" />
+	<bean id="MessagingProvider.ZipStream" class="org.apache.taverna.server.master.rest.handler.ZipStreamHandler" />
+	<bean id="MessagingProvider.URIList" class="org.apache.taverna.server.master.rest.handler.URIListHandler" />
 	<bean id="Interceptor.FlushThreadLocalCache"
-		class="org.taverna.server.master.utils.FlushThreadLocalCacheInterceptor"
+		class="org.apache.taverna.server.master.utils.FlushThreadLocalCacheInterceptor"
 		lazy-init="false">
 	</bean>
 </beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/webappBeans.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
index 6e4237e..16a9867 100644
--- a/taverna-server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
@@ -42,7 +42,7 @@ limitations under the License.
 	<import resource="providers.xml" />
 
 	<context:annotation-config />
-	<context:component-scan base-package="org.taverna.server" />
+	<context:component-scan base-package="org.apache.taverna.server" />
 	<bean id="servletContextPropertyConfigurer"
 		class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
 		<property name="ignoreUnresolvablePlaceholders" value="true" />
@@ -52,7 +52,7 @@ limitations under the License.
 	</bean>
 
 	<jaxws:server id="master_SOAP"
-		serviceClass="org.taverna.server.master.TavernaServer" address="/soap">
+		serviceClass="org.apache.taverna.server.master.TavernaServer" address="/soap">
 		<jaxws:serviceBean>
 			<ref bean="webapp" />
 		</jaxws:serviceBean>
@@ -161,12 +161,12 @@ limitations under the License.
 		<entry key="http://ns.taverna.org.uk/2010/run/" value="" />
 	</util:map>
 
-	<bean id="root_facade" class="org.taverna.server.master.facade.Facade">
+	<bean id="root_facade" class="org.apache.taverna.server.master.facade.Facade">
 		<property name="file" value="/welcome.html" />
 		<property name="contextualizer" ref="contextualizer" />
 	</bean>
 
-	<bean class="org.taverna.server.master.common.Uri.Rewriter"
+	<bean class="org.apache.taverna.server.master.common.Uri.Rewriter"
 		autowire="byType" id="URI-Rewriter-Thunk">
 		<property name="suppressSecurity" value="${suppressRewriteEngine}" />
 		<property name="rewriteTarget" value="${default.webapp}" />
@@ -177,7 +177,7 @@ limitations under the License.
 	</security:authentication-manager>
 
 	<bean id="WSDLHeadOptionsInterceptor"
-		class="org.taverna.server.master.utils.WSDLHeadOptionsInterceptor" />
+		class="org.apache.taverna.server.master.utils.WSDLHeadOptionsInterceptor" />
 	<cxf:bus>
 		<cxf:inInterceptors>
 			<ref bean="WSDLHeadOptionsInterceptor" />

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/JaxbSanityTest.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/JaxbSanityTest.java
index 79fc9bf..6a97de6 100644
--- a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/JaxbSanityTest.java
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/JaxbSanityTest.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -33,41 +33,41 @@ import javax.xml.transform.stream.StreamResult;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.taverna.server.master.admin.Admin;
-import org.taverna.server.master.common.Credential.KeyPair;
-import org.taverna.server.master.common.Credential.Password;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.common.InputDescription;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.rest.DirectoryContents;
-import org.taverna.server.master.rest.ListenerDefinition;
-import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
-import org.taverna.server.master.rest.TavernaServerInputREST.InDesc;
-import org.taverna.server.master.rest.TavernaServerInputREST.InputsDescriptor;
-import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
-import org.taverna.server.master.rest.TavernaServerListenersREST.Listeners;
-import org.taverna.server.master.rest.TavernaServerListenersREST.Properties;
-import org.taverna.server.master.rest.TavernaServerListenersREST.PropertyDescription;
-import org.taverna.server.master.rest.TavernaServerREST.EnabledNotificationFabrics;
-import org.taverna.server.master.rest.TavernaServerREST.PermittedListeners;
-import org.taverna.server.master.rest.TavernaServerREST.PermittedWorkflows;
-import org.taverna.server.master.rest.TavernaServerREST.PolicyView.CapabilityList;
-import org.taverna.server.master.rest.TavernaServerREST.PolicyView.PolicyDescription;
-import org.taverna.server.master.rest.TavernaServerREST.RunList;
-import org.taverna.server.master.rest.TavernaServerREST.ServerDescription;
-import org.taverna.server.master.rest.TavernaServerRunREST.RunDescription;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-import org.taverna.server.master.rest.TavernaServerSecurityREST.CredentialHolder;
-import org.taverna.server.master.soap.DirEntry;
-import org.taverna.server.master.soap.FileContents;
-import org.taverna.server.master.soap.PermissionList;
+import org.apache.taverna.server.master.admin.Admin;
+import org.apache.taverna.server.master.common.Credential.KeyPair;
+import org.apache.taverna.server.master.common.Credential.Password;
+import org.apache.taverna.server.master.common.Capability;
+import org.apache.taverna.server.master.common.DirEntryReference;
+import org.apache.taverna.server.master.common.InputDescription;
+import org.apache.taverna.server.master.common.Permission;
+import org.apache.taverna.server.master.common.ProfileList;
+import org.apache.taverna.server.master.common.RunReference;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Trust;
+import org.apache.taverna.server.master.common.Uri;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.rest.DirectoryContents;
+import org.apache.taverna.server.master.rest.ListenerDefinition;
+import org.apache.taverna.server.master.rest.MakeOrUpdateDirEntry;
+import org.apache.taverna.server.master.rest.TavernaServerInputREST.InDesc;
+import org.apache.taverna.server.master.rest.TavernaServerInputREST.InputsDescriptor;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST.Listeners;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST.Properties;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST.PropertyDescription;
+import org.apache.taverna.server.master.rest.TavernaServerREST.EnabledNotificationFabrics;
+import org.apache.taverna.server.master.rest.TavernaServerREST.PermittedListeners;
+import org.apache.taverna.server.master.rest.TavernaServerREST.PermittedWorkflows;
+import org.apache.taverna.server.master.rest.TavernaServerREST.PolicyView.CapabilityList;
+import org.apache.taverna.server.master.rest.TavernaServerREST.PolicyView.PolicyDescription;
+import org.apache.taverna.server.master.rest.TavernaServerREST.RunList;
+import org.apache.taverna.server.master.rest.TavernaServerREST.ServerDescription;
+import org.apache.taverna.server.master.rest.TavernaServerRunREST.RunDescription;
+import org.apache.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.apache.taverna.server.master.rest.TavernaServerSecurityREST.CredentialHolder;
+import org.apache.taverna.server.master.soap.DirEntry;
+import org.apache.taverna.server.master.soap.FileContents;
+import org.apache.taverna.server.master.soap.PermissionList;
 
 /**
  * This test file ensures that the JAXB bindings will work once deployed instead

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/TavernaServerImplTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/TavernaServerImplTest.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/TavernaServerImplTest.java
index b1191f1..687fd6d 100644
--- a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/TavernaServerImplTest.java
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/TavernaServerImplTest.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,18 +23,18 @@ import static org.junit.Assert.assertNotNull;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.mocks.ExampleRun;
-import org.taverna.server.master.mocks.MockPolicy;
-import org.taverna.server.master.mocks.SimpleListenerFactory;
-import org.taverna.server.master.mocks.SimpleNonpersistentRunStore;
+import org.apache.taverna.server.master.api.ManagementModel;
+import org.apache.taverna.server.master.common.RunReference;
+import org.apache.taverna.server.master.exceptions.BadPropertyValueException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.mocks.ExampleRun;
+import org.apache.taverna.server.master.mocks.MockPolicy;
+import org.apache.taverna.server.master.mocks.SimpleListenerFactory;
+import org.apache.taverna.server.master.mocks.SimpleNonpersistentRunStore;
 
 public class TavernaServerImplTest {
 	private TavernaServer server;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/WorkflowSerializationTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/WorkflowSerializationTest.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/WorkflowSerializationTest.java
index 1217c1f..0c4e87f 100644
--- a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/WorkflowSerializationTest.java
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/WorkflowSerializationTest.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -16,8 +16,8 @@ package org.taverna.server.master;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
+import static org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
+import static org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -31,7 +31,7 @@ import javax.xml.parsers.ParserConfigurationException;
 
 import org.junit.Assert;
 import org.junit.Test;
-import org.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.common.Workflow;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/ExampleRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/ExampleRun.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/ExampleRun.java
index 862cf2c..5c8ca97 100644
--- a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/ExampleRun.java
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/ExampleRun.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.mocks;
+package org.apache.taverna.server.master.mocks;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,7 +21,7 @@ package org.taverna.server.master.mocks;
 import static java.util.Calendar.MINUTE;
 import static java.util.Collections.unmodifiableList;
 import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.common.Status.Initialized;
+import static org.apache.taverna.server.master.common.Status.Initialized;
 
 import java.io.IOException;
 import java.security.GeneralSecurityException;
@@ -38,23 +38,23 @@ import javax.ws.rs.core.HttpHeaders;
 import javax.xml.ws.handler.MessageContext;
 
 import org.springframework.security.core.context.SecurityContext;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.factories.RunFactory;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.common.Credential;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Trust;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.InvalidCredentialException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.factories.RunFactory;
+import org.apache.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.interfaces.Input;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.SecurityContextFactory;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 @SuppressWarnings("serial")
 public class ExampleRun implements TavernaRun, TavernaSecurityContext {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/MockPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/MockPolicy.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/MockPolicy.java
index b61fc10..5a65874 100644
--- a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/MockPolicy.java
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/MockPolicy.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.mocks;
+package org.apache.taverna.server.master.mocks;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,12 +19,12 @@ package org.taverna.server.master.mocks;
 import java.util.HashSet;
 import java.util.Set;
 
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoDestroyException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 public class MockPolicy extends SimpleServerPolicy {
 	public MockPolicy() {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleListenerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleListenerFactory.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleListenerFactory.java
index 7d9c998..397aefe 100644
--- a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleListenerFactory.java
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleListenerFactory.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.mocks;
+package org.apache.taverna.server.master.mocks;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,10 +21,10 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.factories.ListenerFactory;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
 
 /**
  * A factory for event listener. The factory is configured using Spring.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleNonpersistentRunStore.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
index 63b6754..72985da 100644
--- a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.mocks;
+package org.apache.taverna.server.master.mocks;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,12 +24,12 @@ import java.util.Map;
 import java.util.Timer;
 import java.util.TimerTask;
 
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.exceptions.NoDestroyException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.interfaces.Policy;
+import org.apache.taverna.server.master.interfaces.RunStore;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * Example of a store for Taverna Workflow Runs.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleServerPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleServerPolicy.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleServerPolicy.java
index 8dd2757..c648b56 100644
--- a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleServerPolicy.java
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleServerPolicy.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.mocks;
+package org.apache.taverna.server.master.mocks;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,13 +19,13 @@ package org.taverna.server.master.mocks;
 import java.net.URI;
 import java.util.List;
 
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoDestroyException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.Policy;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.utils.UsernamePrincipal;
 
 /**
  * A very simple (and unsafe) security model. The number of runs is configurable

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/test/resources/example.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/resources/example.xml b/taverna-server-webapp/src/test/resources/example.xml
index 5a00c62..ac788d1 100644
--- a/taverna-server-webapp/src/test/resources/example.xml
+++ b/taverna-server-webapp/src/test/resources/example.xml
@@ -19,7 +19,7 @@ limitations under the License.
 	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-2.0.xsd">
 
-	<bean id="policy" class="org.taverna.server.master.mocks.SimpleServerPolicy"
+	<bean id="policy" class="org.apache.taverna.server.master.mocks.SimpleServerPolicy"
 		lazy-init="false" scope="singleton">
 		<property name="maxRuns" value="1">
 			<description>
@@ -33,16 +33,16 @@ limitations under the License.
 		</property>
 	</bean>
 
-	<bean id="runFactory" class="org.taverna.server.master.mocks.ExampleRun$Builder">
+	<bean id="runFactory" class="org.apache.taverna.server.master.mocks.ExampleRun$Builder">
 		<constructor-arg type="int" value="10" /> <!-- "initialLifetimeMinutes" -->
 	</bean>
 
 	<bean id="runCatalog" scope="singleton"
-		class="org.taverna.server.master.mocks.SimpleNonpersistentRunStore">
+		class="org.apache.taverna.server.master.mocks.SimpleNonpersistentRunStore">
 		<property name="policy" ref="policy" />
 	</bean>
 
-	<bean id="listenerFactory" class="org.taverna.server.master.mocks.SimpleListenerFactory">
+	<bean id="listenerFactory" class="org.apache.taverna.server.master.mocks.SimpleListenerFactory">
 		<property name="builders">
 			<description>
 				This map describes how to build each type of supported
@@ -50,7 +50,7 @@ limitations under the License.
 				a listeners should be installed using its properties, as shown. The
 				"key" is the type, the "class" is the builder for actual instances
 				(which must be an instance of
-				org.taverna.server.master.factories.SimpleListenerFactory.Builder)
+				org.apache.taverna.server.master.factories.SimpleListenerFactory.Builder)
 				and any policies and installation-specific configurations are
 				characterised by properties such as "sitePolicy" below.
 			</description>
@@ -58,7 +58,7 @@ limitations under the License.
 				<!--						<entry key="exampleListener">-->
 				<!--
 					<bean
-					class="org.taverna.server.master.example.ExampleListener$Builder">
+					class="org.apache.taverna.server.master.example.ExampleListener$Builder">
 				-->
 				<!--								<property name="sitePolicy">-->
 				<!--									<value>Just an example!</value>-->

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-worker/pom.xml b/taverna-server-worker/pom.xml
index 4b8df5d..56c496c 100644
--- a/taverna-server-worker/pom.xml
+++ b/taverna-server-worker/pom.xml
@@ -29,7 +29,7 @@ limitations under the License.
     This is the implementation of the factory process that is started up by the web application to manage executing Taverna Workflow executeworkflow.sh calls. Also provides per-user access to filestore.</description>
 
 	<properties>
-		<workerMainClass>org.taverna.server.localworker.impl.TavernaRunManager</workerMainClass>
+		<workerMainClass>org.apache.taverna.server.localworker.impl.TavernaRunManager</workerMainClass>
 	</properties>
 
 	<dependencies>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Constants.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Constants.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Constants.java
index 4ee24ad..e0c091e 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Constants.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Constants.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.api;
+package org.apache.taverna.server.localworker.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/RunAccounting.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/RunAccounting.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/RunAccounting.java
index dd18db0..e4e0dfd 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/RunAccounting.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/RunAccounting.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.api;
+package org.apache.taverna.server.localworker.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Worker.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Worker.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Worker.java
index 52c7009..078096d 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Worker.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/Worker.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.api;
+package org.apache.taverna.server.localworker.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,11 +22,11 @@ import java.io.File;
 import java.util.List;
 import java.util.Map;
 
-import org.taverna.server.localworker.impl.LocalWorker;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.apache.taverna.server.localworker.impl.LocalWorker;
+import org.apache.taverna.server.localworker.remote.ImplementationException;
+import org.apache.taverna.server.localworker.remote.RemoteListener;
+import org.apache.taverna.server.localworker.remote.RemoteStatus;
+import org.apache.taverna.server.localworker.server.UsageRecordReceiver;
 
 /**
  * The interface between the connectivity layer and the thunk to the

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/WorkerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/WorkerFactory.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/WorkerFactory.java
index 0fd2d20..6785c11 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/WorkerFactory.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/api/WorkerFactory.java
@@ -1,4 +1,4 @@
-package org.taverna.server.localworker.api;
+package org.apache.taverna.server.localworker.api;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/DirectoryDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/DirectoryDelegate.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/DirectoryDelegate.java
index 6b7ba77..3e2513a 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/DirectoryDelegate.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/DirectoryDelegate.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.impl;
+package org.apache.taverna.server.localworker.impl;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -21,7 +21,7 @@ package org.taverna.server.localworker.impl;
 import static org.apache.commons.io.FileUtils.forceDelete;
 import static org.apache.commons.io.FileUtils.forceMkdir;
 import static org.apache.commons.io.FileUtils.touch;
-import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedNewFile;
+import static org.apache.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedNewFile;
 
 import java.io.File;
 import java.io.IOException;
@@ -36,9 +36,9 @@ import javax.annotation.Nonnull;
 
 import org.apache.commons.collections.MapIterator;
 import org.apache.commons.collections.map.ReferenceMap;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
-import org.taverna.server.localworker.remote.RemoteFile;
+import org.apache.taverna.server.localworker.remote.RemoteDirectory;
+import org.apache.taverna.server.localworker.remote.RemoteDirectoryEntry;
+import org.apache.taverna.server.localworker.remote.RemoteFile;
 
 /**
  * This class acts as a remote-aware delegate for the workflow run's working

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/FileDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/FileDelegate.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/FileDelegate.java
index 8dd9ede..3f1f5d8 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/FileDelegate.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/FileDelegate.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.impl;
+package org.apache.taverna.server.localworker.impl;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -34,8 +34,8 @@ import java.util.Date;
 
 import javax.annotation.Nonnull;
 
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteFile;
+import org.apache.taverna.server.localworker.remote.RemoteDirectory;
+import org.apache.taverna.server.localworker.remote.RemoteFile;
 
 /**
  * This class acts as a remote-aware delegate for the files in a workflow run's

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/LocalWorker.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/LocalWorker.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/LocalWorker.java
index f96f91c..2effd53 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/LocalWorker.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/LocalWorker.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.impl;
+package org.apache.taverna.server.localworker.impl;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -30,19 +30,19 @@ import static org.apache.commons.io.FileUtils.forceDelete;
 import static org.apache.commons.io.FileUtils.forceMkdir;
 import static org.apache.commons.io.FileUtils.writeByteArrayToFile;
 import static org.apache.commons.io.FileUtils.writeLines;
-import static org.taverna.server.localworker.api.Constants.HELIO_TOKEN_NAME;
-import static org.taverna.server.localworker.api.Constants.KEYSTORE_FILE;
-import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
-import static org.taverna.server.localworker.api.Constants.SECURITY_DIR_NAME;
-import static org.taverna.server.localworker.api.Constants.SHARED_DIR_PROP;
-import static org.taverna.server.localworker.api.Constants.SUBDIR_LIST;
-import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
-import static org.taverna.server.localworker.api.Constants.TRUSTSTORE_FILE;
-import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedFile;
-import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
-import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
-import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
-import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
+import static org.apache.taverna.server.localworker.api.Constants.HELIO_TOKEN_NAME;
+import static org.apache.taverna.server.localworker.api.Constants.KEYSTORE_FILE;
+import static org.apache.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
+import static org.apache.taverna.server.localworker.api.Constants.SECURITY_DIR_NAME;
+import static org.apache.taverna.server.localworker.api.Constants.SHARED_DIR_PROP;
+import static org.apache.taverna.server.localworker.api.Constants.SUBDIR_LIST;
+import static org.apache.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
+import static org.apache.taverna.server.localworker.api.Constants.TRUSTSTORE_FILE;
+import static org.apache.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedFile;
+import static org.apache.taverna.server.localworker.remote.RemoteStatus.Finished;
+import static org.apache.taverna.server.localworker.remote.RemoteStatus.Initialized;
+import static org.apache.taverna.server.localworker.remote.RemoteStatus.Operating;
+import static org.apache.taverna.server.localworker.remote.RemoteStatus.Stopped;
 
 import java.io.File;
 import java.io.IOException;
@@ -59,18 +59,18 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.UUID;
 
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.api.WorkerFactory;
-import org.taverna.server.localworker.remote.IllegalStateTransitionException;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteInput;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteSecurityContext;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.remote.StillWorkingOnItException;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.apache.taverna.server.localworker.api.Worker;
+import org.apache.taverna.server.localworker.api.WorkerFactory;
+import org.apache.taverna.server.localworker.remote.IllegalStateTransitionException;
+import org.apache.taverna.server.localworker.remote.ImplementationException;
+import org.apache.taverna.server.localworker.remote.RemoteDirectory;
+import org.apache.taverna.server.localworker.remote.RemoteInput;
+import org.apache.taverna.server.localworker.remote.RemoteListener;
+import org.apache.taverna.server.localworker.remote.RemoteSecurityContext;
+import org.apache.taverna.server.localworker.remote.RemoteSingleRun;
+import org.apache.taverna.server.localworker.remote.RemoteStatus;
+import org.apache.taverna.server.localworker.remote.StillWorkingOnItException;
+import org.apache.taverna.server.localworker.server.UsageRecordReceiver;
 
 /**
  * This class implements one side of the connection between the Taverna Server

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/TavernaRunManager.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/TavernaRunManager.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/TavernaRunManager.java
index 167302c..5ce03c2 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/TavernaRunManager.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/TavernaRunManager.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.impl;
+package org.apache.taverna.server.localworker.impl;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,12 +25,12 @@ import static java.lang.System.out;
 import static java.lang.System.setProperty;
 import static java.lang.System.setSecurityManager;
 import static java.rmi.registry.LocateRegistry.getRegistry;
-import static org.taverna.server.localworker.api.Constants.DEATH_DELAY;
-import static org.taverna.server.localworker.api.Constants.LOCALHOST;
-import static org.taverna.server.localworker.api.Constants.RMI_HOST_PROP;
-import static org.taverna.server.localworker.api.Constants.SECURITY_POLICY_FILE;
-import static org.taverna.server.localworker.api.Constants.SEC_POLICY_PROP;
-import static org.taverna.server.localworker.api.Constants.UNSECURE_PROP;
+import static org.apache.taverna.server.localworker.api.Constants.DEATH_DELAY;
+import static org.apache.taverna.server.localworker.api.Constants.LOCALHOST;
+import static org.apache.taverna.server.localworker.api.Constants.RMI_HOST_PROP;
+import static org.apache.taverna.server.localworker.api.Constants.SECURITY_POLICY_FILE;
+import static org.apache.taverna.server.localworker.api.Constants.SEC_POLICY_PROP;
+import static org.apache.taverna.server.localworker.api.Constants.UNSECURE_PROP;
 
 import java.io.ByteArrayInputStream;
 import java.net.URI;
@@ -44,12 +44,12 @@ import java.util.Map;
 import java.util.UUID;
 
 import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
-import org.taverna.server.localworker.api.RunAccounting;
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.api.WorkerFactory;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.apache.taverna.server.localworker.api.RunAccounting;
+import org.apache.taverna.server.localworker.api.Worker;
+import org.apache.taverna.server.localworker.api.WorkerFactory;
+import org.apache.taverna.server.localworker.remote.RemoteRunFactory;
+import org.apache.taverna.server.localworker.remote.RemoteSingleRun;
+import org.apache.taverna.server.localworker.server.UsageRecordReceiver;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/WorkerCore.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/WorkerCore.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/WorkerCore.java
index 4aa6605..c2b2050 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/WorkerCore.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/WorkerCore.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.impl;
+package org.apache.taverna.server.localworker.impl;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -31,28 +31,28 @@ import static org.apache.commons.io.FileUtils.forceDelete;
 import static org.apache.commons.io.FileUtils.sizeOfDirectory;
 import static org.apache.commons.io.FileUtils.write;
 import static org.apache.commons.io.IOUtils.copy;
-import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_DIRECTORY;
-import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_PASSWORD;
-import static org.taverna.server.localworker.api.Constants.DEATH_TIME;
-import static org.taverna.server.localworker.api.Constants.DEFAULT_LISTENER_NAME;
-import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
-import static org.taverna.server.localworker.api.Constants.START_WAIT_TIME;
-import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
-import static org.taverna.server.localworker.api.Constants.TIME;
-import static org.taverna.server.localworker.impl.Status.Aborted;
-import static org.taverna.server.localworker.impl.Status.Completed;
-import static org.taverna.server.localworker.impl.Status.Failed;
-import static org.taverna.server.localworker.impl.Status.Held;
-import static org.taverna.server.localworker.impl.Status.Started;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionFeedPath;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionHost;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionPort;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionWebdavPath;
-import static org.taverna.server.localworker.impl.WorkerCore.pmap;
-import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
-import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
-import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
-import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
+import static org.apache.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_DIRECTORY;
+import static org.apache.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_PASSWORD;
+import static org.apache.taverna.server.localworker.api.Constants.DEATH_TIME;
+import static org.apache.taverna.server.localworker.api.Constants.DEFAULT_LISTENER_NAME;
+import static org.apache.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
+import static org.apache.taverna.server.localworker.api.Constants.START_WAIT_TIME;
+import static org.apache.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
+import static org.apache.taverna.server.localworker.api.Constants.TIME;
+import static org.apache.taverna.server.localworker.impl.Status.Aborted;
+import static org.apache.taverna.server.localworker.impl.Status.Completed;
+import static org.apache.taverna.server.localworker.impl.Status.Failed;
+import static org.apache.taverna.server.localworker.impl.Status.Held;
+import static org.apache.taverna.server.localworker.impl.Status.Started;
+import static org.apache.taverna.server.localworker.impl.TavernaRunManager.interactionFeedPath;
+import static org.apache.taverna.server.localworker.impl.TavernaRunManager.interactionHost;
+import static org.apache.taverna.server.localworker.impl.TavernaRunManager.interactionPort;
+import static org.apache.taverna.server.localworker.impl.TavernaRunManager.interactionWebdavPath;
+import static org.apache.taverna.server.localworker.impl.WorkerCore.pmap;
+import static org.apache.taverna.server.localworker.remote.RemoteStatus.Finished;
+import static org.apache.taverna.server.localworker.remote.RemoteStatus.Initialized;
+import static org.apache.taverna.server.localworker.remote.RemoteStatus.Operating;
+import static org.apache.taverna.server.localworker.remote.RemoteStatus.Stopped;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -87,13 +87,13 @@ import javax.xml.datatype.DatatypeConfigurationException;
 import javax.xml.ws.Holder;
 
 import org.apache.taverna.server.usagerecord.JobUsageRecord;
-import org.taverna.server.localworker.api.RunAccounting;
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.impl.utils.TimingOutTask;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.apache.taverna.server.localworker.api.RunAccounting;
+import org.apache.taverna.server.localworker.api.Worker;
+import org.apache.taverna.server.localworker.impl.utils.TimingOutTask;
+import org.apache.taverna.server.localworker.remote.ImplementationException;
+import org.apache.taverna.server.localworker.remote.RemoteListener;
+import org.apache.taverna.server.localworker.remote.RemoteStatus;
+import org.apache.taverna.server.localworker.server.UsageRecordReceiver;
 
 /**
  * The core class that connects to a Taverna command-line workflow execution

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/FilenameVerifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/FilenameVerifier.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/FilenameVerifier.java
index fa2e117..cf9a0c9 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/FilenameVerifier.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/FilenameVerifier.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.impl.utils;
+package org.apache.taverna.server.localworker.impl.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/TimingOutTask.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/TimingOutTask.java b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/TimingOutTask.java
index c5b1b7b..68fdc1f 100644
--- a/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/TimingOutTask.java
+++ b/taverna-server-worker/src/main/java/org/apache/taverna/server/localworker/impl/utils/TimingOutTask.java
@@ -1,4 +1,4 @@
-package org.taverna.server.localworker.impl.utils;
+package org.apache.taverna.server.localworker.impl.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-worker/src/test/java/org/apache/taverna/server/localworker/impl/LocalWorkerTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/test/java/org/apache/taverna/server/localworker/impl/LocalWorkerTest.java b/taverna-server-worker/src/test/java/org/apache/taverna/server/localworker/impl/LocalWorkerTest.java
index 084738f..5cf9e18 100644
--- a/taverna-server-worker/src/test/java/org/apache/taverna/server/localworker/impl/LocalWorkerTest.java
+++ b/taverna-server-worker/src/test/java/org/apache/taverna/server/localworker/impl/LocalWorkerTest.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.impl;
+package org.apache.taverna.server.localworker.impl;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,7 +25,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
-import static org.taverna.server.localworker.impl.LocalWorker.DO_MKDIR;
+import static org.apache.taverna.server.localworker.impl.LocalWorker.DO_MKDIR;
 
 import java.io.File;
 import java.rmi.RemoteException;
@@ -40,15 +40,15 @@ import java.util.TreeMap;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.api.WorkerFactory;
-import org.taverna.server.localworker.remote.IllegalStateTransitionException;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteInput;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.apache.taverna.server.localworker.api.Worker;
+import org.apache.taverna.server.localworker.api.WorkerFactory;
+import org.apache.taverna.server.localworker.remote.IllegalStateTransitionException;
+import org.apache.taverna.server.localworker.remote.ImplementationException;
+import org.apache.taverna.server.localworker.remote.RemoteDirectory;
+import org.apache.taverna.server.localworker.remote.RemoteInput;
+import org.apache.taverna.server.localworker.remote.RemoteListener;
+import org.apache.taverna.server.localworker.remote.RemoteStatus;
+import org.apache.taverna.server.localworker.server.UsageRecordReceiver;
 
 public class LocalWorkerTest {
 	LocalWorker lw;



[18/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java
deleted file mode 100644
index 4844147..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java
+++ /dev/null
@@ -1,1438 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static java.lang.Math.min;
-import static java.util.Collections.emptyMap;
-import static java.util.Collections.sort;
-import static java.util.UUID.randomUUID;
-import static javax.ws.rs.core.Response.created;
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static javax.xml.ws.handler.MessageContext.HTTP_REQUEST_HEADERS;
-import static javax.xml.ws.handler.MessageContext.PATH_INFO;
-import static org.apache.commons.io.IOUtils.toByteArray;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.TavernaServerSupport.PROV_BUNDLE;
-import static org.taverna.server.master.common.DirEntryReference.newInstance;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Roles.SELF;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.common.Status.Initialized;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.soap.DirEntry.convert;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.PreDestroy;
-import javax.annotation.Resource;
-import javax.annotation.security.DeclareRoles;
-import javax.annotation.security.RolesAllowed;
-import javax.jws.WebService;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.JAXBException;
-import javax.xml.ws.WebServiceContext;
-
-import org.apache.commons.logging.Log;
-import org.apache.cxf.annotations.WSDLDocumentation;
-import org.apache.taverna.server.usagerecord.JobUsageRecord;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.SupportAware;
-import org.taverna.server.master.api.TavernaServerBean;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.common.InputDescription;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoCredentialException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.NotOwnerException;
-import org.taverna.server.master.exceptions.OverloadedException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.notification.NotificationEngine;
-import org.taverna.server.master.notification.atom.EventDAO;
-import org.taverna.server.master.rest.TavernaServerREST;
-import org.taverna.server.master.rest.TavernaServerREST.EnabledNotificationFabrics;
-import org.taverna.server.master.rest.TavernaServerREST.PermittedListeners;
-import org.taverna.server.master.rest.TavernaServerREST.PermittedWorkflows;
-import org.taverna.server.master.rest.TavernaServerREST.PolicyView;
-import org.taverna.server.master.rest.TavernaServerRunREST;
-import org.taverna.server.master.soap.DirEntry;
-import org.taverna.server.master.soap.FileContents;
-import org.taverna.server.master.soap.PermissionList;
-import org.taverna.server.master.soap.TavernaServerSOAP;
-import org.taverna.server.master.soap.WrappedWorkflow;
-import org.taverna.server.master.soap.ZippedDirectory;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-import org.taverna.server.port_description.OutputDescription;
-
-/**
- * The core implementation of the web application.
- * 
- * @author Donal Fellows
- */
-@Path("/")
-@DeclareRoles({ USER, ADMIN })
-@WebService(endpointInterface = "org.taverna.server.master.soap.TavernaServerSOAP", serviceName = "TavernaServer", targetNamespace = SERVER_SOAP)
-@WSDLDocumentation("An instance of Taverna " + Version.JAVA + " Server.")
-public abstract class TavernaServer implements TavernaServerSOAP,
-		TavernaServerREST, TavernaServerBean {
-	/**
-	 * The root of descriptions of the server in JMX.
-	 */
-	public static final String JMX_ROOT = "Taverna:group=Server-"
-			+ Version.JAVA + ",name=";
-
-	/** The logger for the server framework. */
-	public Log log = getLog("Taverna.Server.Webapp");
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-	// CONNECTIONS TO JMX, SPRING AND CXF
-
-	@Resource
-	WebServiceContext jaxws;
-	@Context
-	private HttpHeaders jaxrsHeaders;
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-	// STATE VARIABLES AND SPRING SETTERS
-
-	/**
-	 * For building descriptions of the expected inputs and actual outputs of a
-	 * workflow.
-	 */
-	private ContentsDescriptorBuilder cdBuilder;
-	/**
-	 * Utilities for accessing files on the local-worker.
-	 */
-	private FilenameUtils fileUtils;
-	/** How notifications are dispatched. */
-	private NotificationEngine notificationEngine;
-	/** Main support class. */
-	private TavernaServerSupport support;
-	/** A storage facility for workflow runs. */
-	private RunStore runStore;
-	/** Encapsulates the policies applied by this server. */
-	private Policy policy;
-	/** Where Atom events come from. */
-	EventDAO eventSource;
-	/** Reference to the main interaction feed. */
-	private String interactionFeed;
-
-	@Override
-	@Required
-	public void setFileUtils(FilenameUtils converter) {
-		this.fileUtils = converter;
-	}
-
-	@Override
-	@Required
-	public void setContentsDescriptorBuilder(ContentsDescriptorBuilder cdBuilder) {
-		this.cdBuilder = cdBuilder;
-	}
-
-	@Override
-	@Required
-	public void setNotificationEngine(NotificationEngine notificationEngine) {
-		this.notificationEngine = notificationEngine;
-	}
-
-	/**
-	 * @param support
-	 *            the support to set
-	 */
-	@Override
-	@Required
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	@Required
-	public void setRunStore(RunStore runStore) {
-		this.runStore = runStore;
-	}
-
-	@Override
-	@Required
-	public void setPolicy(Policy policy) {
-		this.policy = policy;
-	}
-
-	@Override
-	@Required
-	public void setEventSource(EventDAO eventSource) {
-		this.eventSource = eventSource;
-	}
-
-	/**
-	 * The location of a service-wide interaction feed, derived from a
-	 * properties file. Expected to be <i>actually</i> not set (to a real
-	 * value).
-	 * 
-	 * @param interactionFeed
-	 *            The URL, which will be resolved relative to the location of
-	 *            the webapp, or the string "<tt>none</tt>" (which corresponds
-	 *            to a <tt>null</tt>).
-	 */
-	public void setInteractionFeed(String interactionFeed) {
-		if ("none".equals(interactionFeed))
-			interactionFeed = null;
-		else if (interactionFeed != null && interactionFeed.startsWith("${"))
-			interactionFeed = null;
-		this.interactionFeed = interactionFeed;
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-	// REST INTERFACE
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public ServerDescription describeService(UriInfo ui) {
-		jaxrsUriInfo.set(new WeakReference<>(ui));
-		return new ServerDescription(ui, resolve(interactionFeed));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public RunList listUsersRuns(UriInfo ui) {
-		jaxrsUriInfo.set(new WeakReference<>(ui));
-		return new RunList(runs(), secure(ui).path("{name}"));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response submitWorkflow(Workflow workflow, UriInfo ui)
-			throws NoUpdateException {
-		jaxrsUriInfo.set(new WeakReference<>(ui));
-		checkCreatePolicy(workflow);
-		String name = support.buildWorkflow(workflow);
-		return created(secure(ui).path("{uuid}").build(name)).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response submitWorkflowByURL(List<URI> referenceList, UriInfo ui)
-			throws NoCreateException {
-		jaxrsUriInfo.set(new WeakReference<>(ui));
-		if (referenceList == null || referenceList.size() == 0)
-			throw new NoCreateException("no workflow URI supplied");
-		URI workflowURI = referenceList.get(0);
-		checkCreatePolicy(workflowURI);
-		Workflow workflow;
-		try {
-			workflow = support.getWorkflowDocumentFromURI(workflowURI);
-		} catch (IOException e) {
-			throw new NoCreateException("could not read workflow", e);
-		}
-		String name = support.buildWorkflow(workflow);
-		return created(secure(ui).path("{uuid}").build(name)).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public int getServerMaxRuns() {
-		return support.getMaxSimultaneousRuns();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public TavernaServerRunREST getRunResource(String runName, UriInfo ui)
-			throws UnknownRunException {
-		jaxrsUriInfo.set(new WeakReference<>(ui));
-		RunREST rr = makeRunInterface();
-		rr.setRun(support.getRun(runName));
-		rr.setRunName(runName);
-		return rr;
-	}
-
-	private ThreadLocal<Reference<UriInfo>> jaxrsUriInfo = new InheritableThreadLocal<>();
-
-	private UriInfo getUriInfo() {
-		if (jaxrsUriInfo.get() == null)
-			return null;
-		return jaxrsUriInfo.get().get();
-	}
-
-	@Override
-	@CallCounted
-	public abstract PolicyView getPolicyDescription();
-
-	@Override
-	@CallCounted
-	public Response serviceOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response runsOptions() {
-		return opt("POST");
-	}
-
-	/**
-	 * Construct a RESTful interface to a run.
-	 * 
-	 * @return The handle to the interface, as decorated by Spring.
-	 */
-	protected abstract RunREST makeRunInterface();
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-	// SOAP INTERFACE
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public RunReference[] listRuns() {
-		ArrayList<RunReference> ws = new ArrayList<>();
-		UriBuilder ub = getRunUriBuilder();
-		for (String runName : runs().keySet())
-			ws.add(new RunReference(runName, ub));
-		return ws.toArray(new RunReference[ws.size()]);
-	}
-
-	private void checkCreatePolicy(Workflow workflow) throws NoCreateException {
-		List<URI> pwu = policy
-				.listPermittedWorkflowURIs(support.getPrincipal());
-		if (pwu == null || pwu.size() == 0)
-			return;
-		throw new NoCreateException("server policy: will only start "
-				+ "workflows sourced from permitted URI list");
-	}
-
-	private void checkCreatePolicy(URI workflowURI) throws NoCreateException {
-		List<URI> pwu = policy
-				.listPermittedWorkflowURIs(support.getPrincipal());
-		if (pwu == null || pwu.size() == 0 || pwu.contains(workflowURI))
-			return;
-		throw new NoCreateException("workflow URI not on permitted list");
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public RunReference submitWorkflow(Workflow workflow)
-			throws NoUpdateException {
-		checkCreatePolicy(workflow);
-		String name = support.buildWorkflow(workflow);
-		return new RunReference(name, getRunUriBuilder());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public RunReference submitWorkflowMTOM(WrappedWorkflow workflow)
-			throws NoUpdateException {
-		Workflow wf;
-		try {
-			wf = workflow.getWorkflow();
-		} catch (IOException e) {
-			throw new NoCreateException(e.getMessage(), e);
-		}
-		checkCreatePolicy(wf);
-		String name = support.buildWorkflow(wf);
-		return new RunReference(name, getRunUriBuilder());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public RunReference submitWorkflowByURI(URI workflowURI)
-			throws NoCreateException {
-		checkCreatePolicy(workflowURI);
-		Workflow workflow;
-		try {
-			workflow = support.getWorkflowDocumentFromURI(workflowURI);
-		} catch (IOException e) {
-			throw new NoCreateException("could not read workflow", e);
-		}
-		String name = support.buildWorkflow(workflow);
-		return new RunReference(name, getRunUriBuilder());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public URI[] getServerWorkflows() {
-		return support.getPermittedWorkflowURIs();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String[] getServerListeners() {
-		List<String> types = support.getListenerTypes();
-		return types.toArray(new String[types.size()]);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String[] getServerNotifiers() {
-		List<String> dispatchers = notificationEngine
-				.listAvailableDispatchers();
-		return dispatchers.toArray(new String[dispatchers.size()]);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public List<Capability> getServerCapabilities() {
-		return support.getCapabilities();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void destroyRun(String runName) throws UnknownRunException,
-			NoUpdateException {
-		support.unregisterRun(runName, null);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getRunDescriptiveName(String runName)
-			throws UnknownRunException {
-		return support.getRun(runName).getName();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunDescriptiveName(String runName, String descriptiveName)
-			throws UnknownRunException, NoUpdateException {
-		TavernaRun run = support.getRun(runName);
-		support.permitUpdate(run);
-		run.setName(descriptiveName);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Workflow getRunWorkflow(String runName) throws UnknownRunException {
-		return support.getRun(runName).getWorkflow();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public WrappedWorkflow getRunWorkflowMTOM(String runName)
-			throws UnknownRunException {
-		WrappedWorkflow ww = new WrappedWorkflow();
-		ww.setWorkflow(support.getRun(runName).getWorkflow());
-		return ww;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public ProfileList getRunWorkflowProfiles(String runName)
-			throws UnknownRunException {
-		return support.getProfileDescriptor(support.getRun(runName)
-				.getWorkflow());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Date getRunExpiry(String runName) throws UnknownRunException {
-		return support.getRun(runName).getExpiry();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunExpiry(String runName, Date d)
-			throws UnknownRunException, NoUpdateException {
-		support.updateExpiry(support.getRun(runName), d);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Date getRunCreationTime(String runName) throws UnknownRunException {
-		return support.getRun(runName).getCreationTimestamp();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Date getRunFinishTime(String runName) throws UnknownRunException {
-		return support.getRun(runName).getFinishTimestamp();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Date getRunStartTime(String runName) throws UnknownRunException {
-		return support.getRun(runName).getStartTimestamp();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Status getRunStatus(String runName) throws UnknownRunException {
-		return support.getRun(runName).getStatus();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String setRunStatus(String runName, Status s)
-			throws UnknownRunException, NoUpdateException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		if (s == Status.Operating && w.getStatus() == Status.Initialized) {
-			if (!support.getAllowStartWorkflowRuns())
-				throw new OverloadedException();
-			try {
-				String issue = w.setStatus(s);
-				if (issue == null)
-					return "";
-				if (issue.isEmpty())
-					return "unknown reason for partial change";
-				return issue;
-			} catch (RuntimeException | NoUpdateException e) {
-				log.info("failed to start run " + runName, e);
-				throw e;
-			}
-		} else {
-			w.setStatus(s);
-			return "";
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getRunStdout(String runName) throws UnknownRunException {
-		try {
-			return support.getProperty(runName, "io", "stdout");
-		} catch (NoListenerException e) {
-			return "";
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getRunStderr(String runName) throws UnknownRunException {
-		try {
-			return support.getProperty(runName, "io", "stderr");
-		} catch (NoListenerException e) {
-			return "";
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public JobUsageRecord getRunUsageRecord(String runName)
-			throws UnknownRunException {
-		try {
-			String ur = support.getProperty(runName, "io", "usageRecord");
-			if (ur.isEmpty())
-				return null;
-			return JobUsageRecord.unmarshal(ur);
-		} catch (NoListenerException e) {
-			return null;
-		} catch (JAXBException e) {
-			log.info("failed to deserialize non-empty usage record", e);
-			return null;
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getRunLog(String runName) throws UnknownRunException {
-		try {
-			return support.getLogs(support.getRun(runName)).get("UTF-8");
-		} catch (UnsupportedEncodingException e) {
-			log.warn("unexpected encoding problem", e);
-			return "";
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public FileContents getRunBundle(String runName)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		File f = fileUtils.getFile(support.getRun(runName), PROV_BUNDLE);
-		FileContents fc = new FileContents();
-		// We *know* the content type, by definition
-		fc.setFile(f, "application/vnd.wf4ever.robundle+zip");
-		return fc;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public boolean getRunGenerateProvenance(String runName)
-			throws UnknownRunException {
-		return support.getRun(runName).getGenerateProvenance();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunGenerateProvenance(String runName, boolean generate)
-			throws UnknownRunException, NoUpdateException {
-		TavernaRun run = support.getRun(runName);
-		support.permitUpdate(run);
-		run.setGenerateProvenance(generate);
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-	// SOAP INTERFACE - Security
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getRunOwner(String runName) throws UnknownRunException {
-		return support.getRun(runName).getSecurityContext().getOwner()
-				.getName();
-	}
-
-	/**
-	 * Look up a security context, applying access control rules for access to
-	 * the parts of the context that are only open to the owner.
-	 * 
-	 * @param runName
-	 *            The name of the workflow run.
-	 * @param initialOnly
-	 *            Whether to check if we're in the initial state.
-	 * @return The security context. Never <tt>null</tt>.
-	 * @throws UnknownRunException
-	 * @throws NotOwnerException
-	 * @throws BadStateChangeException
-	 */
-	private TavernaSecurityContext getRunSecurityContext(String runName,
-			boolean initialOnly) throws UnknownRunException, NotOwnerException,
-			BadStateChangeException {
-		TavernaRun run = support.getRun(runName);
-		TavernaSecurityContext c = run.getSecurityContext();
-		if (!c.getOwner().equals(support.getPrincipal()))
-			throw new NotOwnerException();
-		if (initialOnly && run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		return c;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Credential[] getRunCredentials(String runName)
-			throws UnknownRunException, NotOwnerException {
-		try {
-			return getRunSecurityContext(runName, false).getCredentials();
-		} catch (BadStateChangeException e) {
-			Error e2 = new Error("impossible");
-			e2.initCause(e);
-			throw e2;
-		}
-	}
-
-	private Credential findCredential(TavernaSecurityContext c, String id)
-			throws NoCredentialException {
-		for (Credential t : c.getCredentials())
-			if (t.id.equals(id))
-				return t;
-		throw new NoCredentialException();
-	}
-
-	private Trust findTrust(TavernaSecurityContext c, String id)
-			throws NoCredentialException {
-		for (Trust t : c.getTrusted())
-			if (t.id.equals(id))
-				return t;
-		throw new NoCredentialException();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String setRunCredential(String runName, String credentialID,
-			Credential credential) throws UnknownRunException,
-			NotOwnerException, InvalidCredentialException,
-			NoCredentialException, BadStateChangeException {
-		TavernaSecurityContext c = getRunSecurityContext(runName, true);
-		if (credentialID == null || credentialID.isEmpty()) {
-			credential.id = randomUUID().toString();
-		} else {
-			credential.id = findCredential(c, credentialID).id;
-		}
-		URI uri = getRunUriBuilder().path("security/credentials/{credid}")
-				.build(runName, credential.id);
-		credential.href = uri.toString();
-		c.validateCredential(credential);
-		c.addCredential(credential);
-		return credential.id;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void deleteRunCredential(String runName, String credentialID)
-			throws UnknownRunException, NotOwnerException,
-			NoCredentialException, BadStateChangeException {
-		getRunSecurityContext(runName, true).deleteCredential(
-				new Credential.Dummy(credentialID));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Trust[] getRunCertificates(String runName)
-			throws UnknownRunException, NotOwnerException {
-		try {
-			return getRunSecurityContext(runName, false).getTrusted();
-		} catch (BadStateChangeException e) {
-			Error e2 = new Error("impossible");
-			e2.initCause(e);
-			throw e2;
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String setRunCertificates(String runName, String certificateID,
-			Trust certificate) throws UnknownRunException, NotOwnerException,
-			InvalidCredentialException, NoCredentialException,
-			BadStateChangeException {
-		TavernaSecurityContext c = getRunSecurityContext(runName, true);
-		if (certificateID == null || certificateID.isEmpty()) {
-			certificate.id = randomUUID().toString();
-		} else {
-			certificate.id = findTrust(c, certificateID).id;
-		}
-		URI uri = getRunUriBuilder().path("security/trusts/{certid}").build(
-				runName, certificate.id);
-		certificate.href = uri.toString();
-		c.validateTrusted(certificate);
-		c.addTrusted(certificate);
-		return certificate.id;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void deleteRunCertificates(String runName, String certificateID)
-			throws UnknownRunException, NotOwnerException,
-			NoCredentialException, BadStateChangeException {
-		TavernaSecurityContext c = getRunSecurityContext(runName, true);
-		Trust toDelete = new Trust();
-		toDelete.id = certificateID;
-		c.deleteTrusted(toDelete);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public PermissionList listRunPermissions(String runName)
-			throws UnknownRunException, NotOwnerException {
-		PermissionList pl = new PermissionList();
-		pl.permission = new ArrayList<>();
-		Map<String, Permission> perm;
-		try {
-			perm = support.getPermissionMap(getRunSecurityContext(runName,
-					false));
-		} catch (BadStateChangeException e) {
-			log.error("unexpected error from internal API", e);
-			perm = emptyMap();
-		}
-		List<String> users = new ArrayList<>(perm.keySet());
-		sort(users);
-		for (String user : users)
-			pl.permission.add(new PermissionList.SinglePermissionMapping(user,
-					perm.get(user)));
-		return pl;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunPermission(String runName, String userName,
-			Permission permission) throws UnknownRunException,
-			NotOwnerException {
-		try {
-			support.setPermission(getRunSecurityContext(runName, false),
-					userName, permission);
-		} catch (BadStateChangeException e) {
-			log.error("unexpected error from internal API", e);
-		}
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-	// SOAP INTERFACE - Filesystem connection
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public OutputDescription getRunOutputDescription(String runName)
-			throws UnknownRunException, BadStateChangeException,
-			FilesystemAccessException, NoDirectoryEntryException {
-		TavernaRun run = support.getRun(runName);
-		if (run.getStatus() == Initialized)
-			throw new BadStateChangeException(
-					"may not get output description in initial state");
-		return cdBuilder.makeOutputDescriptor(run, null);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public DirEntry[] getRunDirectoryContents(String runName, DirEntry d)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		List<DirEntry> result = new ArrayList<>();
-		for (DirectoryEntry e : fileUtils.getDirectory(support.getRun(runName),
-				convert(d)).getContents())
-			result.add(convert(newInstance(null, e)));
-		return result.toArray(new DirEntry[result.size()]);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public byte[] getRunDirectoryAsZip(String runName, DirEntry d)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		try {
-			return toByteArray(fileUtils.getDirectory(support.getRun(runName),
-					convert(d)).getContentsAsZip());
-		} catch (IOException e) {
-			throw new FilesystemAccessException("problem serializing ZIP data",
-					e);
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public ZippedDirectory getRunDirectoryAsZipMTOM(String runName, DirEntry d)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		return new ZippedDirectory(fileUtils.getDirectory(
-				support.getRun(runName), convert(d)));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public DirEntry makeRunDirectory(String runName, DirEntry parent,
-			String name) throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		Directory dir = fileUtils.getDirectory(w, convert(parent))
-				.makeSubdirectory(support.getPrincipal(), name);
-		return convert(newInstance(null, dir));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public DirEntry makeRunFile(String runName, DirEntry parent, String name)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		File f = fileUtils.getDirectory(w, convert(parent)).makeEmptyFile(
-				support.getPrincipal(), name);
-		return convert(newInstance(null, f));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void destroyRunDirectoryEntry(String runName, DirEntry d)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		fileUtils.getDirEntry(w, convert(d)).destroy();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public byte[] getRunFileContents(String runName, DirEntry d)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		File f = fileUtils.getFile(support.getRun(runName), convert(d));
-		return f.getContents(0, -1);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunFileContents(String runName, DirEntry d,
-			byte[] newContents) throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		fileUtils.getFile(w, convert(d)).setContents(newContents);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public FileContents getRunFileContentsMTOM(String runName, DirEntry d)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		File f = fileUtils.getFile(support.getRun(runName), convert(d));
-		FileContents fc = new FileContents();
-		fc.setFile(f, support.getEstimatedContentType(f));
-		return fc;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunFileContentsFromURI(String runName,
-			DirEntryReference file, URI reference)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException {
-		TavernaRun run = support.getRun(runName);
-		support.permitUpdate(run);
-		File f = fileUtils.getFile(run, file);
-		try {
-			support.copyDataToFile(reference, f);
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"problem transferring data from URI", e);
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunFileContentsMTOM(String runName, FileContents newContents)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException {
-		TavernaRun run = support.getRun(runName);
-		support.permitUpdate(run);
-		File f = fileUtils.getFile(run, newContents.name);
-		f.setContents(new byte[0]);
-		support.copyDataToFile(newContents.fileData, f);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getRunFileType(String runName, DirEntry d)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		return support.getEstimatedContentType(fileUtils.getFile(
-				support.getRun(runName), convert(d)));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public long getRunFileLength(String runName, DirEntry d)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		return fileUtils.getFile(support.getRun(runName), convert(d)).getSize();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Date getRunFileModified(String runName, DirEntry d)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		return fileUtils.getFile(support.getRun(runName), convert(d))
-				.getModificationDate();
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-	// SOAP INTERFACE - Run listeners
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String[] getRunListeners(String runName) throws UnknownRunException {
-		TavernaRun w = support.getRun(runName);
-		List<String> result = new ArrayList<>();
-		for (Listener l : w.getListeners())
-			result.add(l.getName());
-		return result.toArray(new String[result.size()]);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String addRunListener(String runName, String listenerType,
-			String configuration) throws UnknownRunException,
-			NoUpdateException, NoListenerException {
-		return support.makeListener(support.getRun(runName), listenerType,
-				configuration).getName();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getRunListenerConfiguration(String runName,
-			String listenerName) throws UnknownRunException,
-			NoListenerException {
-		return support.getListener(runName, listenerName).getConfiguration();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String[] getRunListenerProperties(String runName, String listenerName)
-			throws UnknownRunException, NoListenerException {
-		return support.getListener(runName, listenerName).listProperties()
-				.clone();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getRunListenerProperty(String runName, String listenerName,
-			String propName) throws UnknownRunException, NoListenerException {
-		return support.getListener(runName, listenerName).getProperty(propName);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunListenerProperty(String runName, String listenerName,
-			String propName, String value) throws UnknownRunException,
-			NoUpdateException, NoListenerException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		Listener l = support.getListener(w, listenerName);
-		try {
-			l.getProperty(propName); // sanity check!
-			l.setProperty(propName, value);
-		} catch (RuntimeException e) {
-			throw new NoListenerException("problem setting property: "
-					+ e.getMessage(), e);
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public InputDescription getRunInputs(String runName)
-			throws UnknownRunException {
-		return new InputDescription(support.getRun(runName));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getRunOutputBaclavaFile(String runName)
-			throws UnknownRunException {
-		return support.getRun(runName).getOutputBaclavaFile();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunInputBaclavaFile(String runName, String fileName)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, BadStateChangeException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		w.setInputBaclavaFile(fileName);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunInputPortFile(String runName, String portName,
-			String portFilename) throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, BadStateChangeException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		Input i = support.getInput(w, portName);
-		if (i == null)
-			i = w.makeInput(portName);
-		i.setFile(portFilename);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunInputPortValue(String runName, String portName,
-			String portValue) throws UnknownRunException, NoUpdateException,
-			BadStateChangeException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		Input i = support.getInput(w, portName);
-		if (i == null)
-			i = w.makeInput(portName);
-		i.setValue(portValue);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunInputPortListDelimiter(String runName, String portName,
-			String delimiter) throws UnknownRunException, NoUpdateException,
-			BadStateChangeException, BadPropertyValueException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		Input i = support.getInput(w, portName);
-		if (i == null)
-			i = w.makeInput(portName);
-		if (delimiter != null && delimiter.isEmpty())
-			delimiter = null;
-		if (delimiter != null) {
-			if (delimiter.length() > 1)
-				throw new BadPropertyValueException("delimiter too long");
-			if (delimiter.charAt(0) < 1 || delimiter.charAt(0) > 127)
-				throw new BadPropertyValueException(
-						"delimiter character must be non-NUL ASCII");
-		}
-		i.setDelimiter(delimiter);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public void setRunOutputBaclavaFile(String runName, String outputFile)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, BadStateChangeException {
-		TavernaRun w = support.getRun(runName);
-		support.permitUpdate(w);
-		w.setOutputBaclavaFile(outputFile);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public org.taverna.server.port_description.InputDescription getRunInputDescriptor(
-			String runName) throws UnknownRunException {
-		return cdBuilder.makeInputDescriptor(support.getRun(runName), null);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getServerStatus() {
-		return support.getAllowNewWorkflowRuns() ? "operational" : "suspended";
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-	// SUPPORT METHODS
-
-	@Override
-	public boolean initObsoleteSOAPSecurity(TavernaSecurityContext c) {
-		try {
-			javax.xml.ws.handler.MessageContext msgCtxt = (jaxws == null ? null
-					: jaxws.getMessageContext());
-			if (msgCtxt == null)
-				return true;
-			c.initializeSecurityFromSOAPContext(msgCtxt);
-			return false;
-		} catch (IllegalStateException e) {
-			/* ignore; not much we can do */
-			return true;
-		}
-	}
-
-	@Override
-	public boolean initObsoleteRESTSecurity(TavernaSecurityContext c) {
-		if (jaxrsHeaders == null)
-			return true;
-		c.initializeSecurityFromRESTContext(jaxrsHeaders);
-		return false;
-	}
-
-	/**
-	 * A creator of substitute {@link URI} builders.
-	 * 
-	 * @return A URI builder configured so that it takes a path parameter that
-	 *         corresponds to the run ID (but with no such ID applied).
-	 */
-	UriBuilder getRunUriBuilder() {
-		return getBaseUriBuilder().path("runs/{uuid}");
-	}
-
-	@Override
-	public UriBuilder getRunUriBuilder(TavernaRun run) {
-		return fromUri(getRunUriBuilder().build(run.getId()));
-	}
-
-	private final String DEFAULT_HOST = "localhost:8080"; // Crappy default
-
-	private String getHostLocation() {
-		@java.lang.SuppressWarnings("unchecked")
-		Map<String, List<String>> headers = (Map<String, List<String>>) jaxws
-				.getMessageContext().get(HTTP_REQUEST_HEADERS);
-		if (headers != null) {
-			List<String> host = headers.get("HOST");
-			if (host != null && !host.isEmpty())
-				return host.get(0);
-		}
-		return DEFAULT_HOST;
-	}
-
-	@Nonnull
-	private URI getPossiblyInsecureBaseUri() {
-		// See if JAX-RS can supply the info
-		UriInfo ui = getUriInfo();
-		if (ui != null && ui.getBaseUri() != null)
-			return ui.getBaseUri();
-		// See if JAX-WS *cannot* supply the info
-		if (jaxws == null || jaxws.getMessageContext() == null)
-			// Hack to make the test suite work
-			return URI.create("http://" + DEFAULT_HOST
-					+ "/taverna-server/rest/");
-		String pathInfo = (String) jaxws.getMessageContext().get(PATH_INFO);
-		pathInfo = pathInfo.replaceFirst("/soap$", "/rest/");
-		pathInfo = pathInfo.replaceFirst("/rest/.+$", "/rest/");
-		return URI.create("http://" + getHostLocation() + pathInfo);
-	}
-
-	@Override
-	public UriBuilder getBaseUriBuilder() {
-		return secure(fromUri(getPossiblyInsecureBaseUri()));
-	}
-
-	@Override
-	@Nullable
-	public String resolve(@Nullable String uri) {
-		if (uri == null)
-			return null;
-		return secure(getPossiblyInsecureBaseUri(), uri).toString();
-	}
-
-	private Map<String, TavernaRun> runs() {
-		return runStore.listRuns(support.getPrincipal(), policy);
-	}
-}
-
-/**
- * RESTful interface to the policies of a Taverna Server installation.
- * 
- * @author Donal Fellows
- */
-class PolicyREST implements PolicyView, SupportAware {
-	private TavernaServerSupport support;
-	private Policy policy;
-	private ListenerFactory listenerFactory;
-	private NotificationEngine notificationEngine;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Required
-	public void setPolicy(Policy policy) {
-		this.policy = policy;
-	}
-
-	@Required
-	public void setListenerFactory(ListenerFactory listenerFactory) {
-		this.listenerFactory = listenerFactory;
-	}
-
-	@Required
-	public void setNotificationEngine(NotificationEngine notificationEngine) {
-		this.notificationEngine = notificationEngine;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public PolicyDescription getDescription(UriInfo ui) {
-		return new PolicyDescription(ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public int getMaxSimultaneousRuns() {
-		Integer limit = policy.getMaxRuns(support.getPrincipal());
-		if (limit == null)
-			return policy.getMaxRuns();
-		return min(limit.intValue(), policy.getMaxRuns());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public PermittedListeners getPermittedListeners() {
-		return new PermittedListeners(
-				listenerFactory.getSupportedListenerTypes());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public PermittedWorkflows getPermittedWorkflows() {
-		return new PermittedWorkflows(policy.listPermittedWorkflowURIs(support
-				.getPrincipal()));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public EnabledNotificationFabrics getEnabledNotifiers() {
-		return new EnabledNotificationFabrics(
-				notificationEngine.listAvailableDispatchers());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public int getMaxOperatingRuns() {
-		return policy.getOperatingLimit();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public CapabilityList getCapabilities() {
-		CapabilityList cl = new CapabilityList();
-		cl.capability.addAll(support.getCapabilities());
-		return cl;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java
deleted file mode 100644
index 533acf5..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static eu.medsea.util.MimeUtil.UNKNOWN_MIME_TYPE;
-import static eu.medsea.util.MimeUtil.getExtensionMimeTypes;
-import static eu.medsea.util.MimeUtil.getMimeType;
-import static java.lang.Math.min;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.springframework.jmx.support.MetricType.COUNTER;
-import static org.springframework.jmx.support.MetricType.GAUGE;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URLConnection;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.activation.DataHandler;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.PreDestroy;
-import javax.ws.rs.WebApplicationException;
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedMetric;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.api.TavernaServerBean;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.factories.RunFactory;
-import org.taverna.server.master.identity.WorkflowInternalAuthProvider.WorkflowSelfAuthority;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.handler.T2FlowDocumentHandler;
-import org.taverna.server.master.utils.CapabilityLister;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.InvocationCounter;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-import org.apache.taverna.scufl2.api.profiles.Profile;
-
-/**
- * Web application support utilities.
- * 
- * @author Donal Fellows
- */
-@ManagedResource(objectName = JMX_ROOT + "Webapp", description = "The main Taverna Server "
-		+ Version.JAVA + " web-application interface.")
-public class TavernaServerSupport {
-	/** The main webapp log. */
-	private Log log = getLog("Taverna.Server.Webapp");
-	private Log accessLog = getLog("Taverna.Server.Webapp.Access");;
-	/** Bean used to log counts of external calls. */
-	private InvocationCounter counter;
-	/** A storage facility for workflow runs. */
-	private RunStore runStore;
-	/** Encapsulates the policies applied by this server. */
-	private Policy policy;
-	/** Connection to the persistent state of this service. */
-	private ManagementModel stateModel;
-	/** A factory for event listeners to attach to workflow runs. */
-	private ListenerFactory listenerFactory;
-	/** A factory for workflow runs. */
-	private RunFactory runFactory;
-	/** How to map the user ID to who to run as. */
-	private LocalIdentityMapper idMapper;
-	/** The code that is coupled to CXF. */
-	private TavernaServerBean webapp;
-	/** How to handle files. */
-	private FilenameUtils fileUtils;
-	/** How to get the server capabilities. */
-	private CapabilityLister capabilitySource;
-	/**
-	 * Whether to log failures during principal retrieval. Should be normally on
-	 * as it indicates a serious problem, but can be switched off for testing.
-	 */
-	private boolean logGetPrincipalFailures = true;
-	private Map<String, String> contentTypeMap;
-	/** Number of bytes to read when guessing the MIME type. */
-	private static final int SAMPLE_SIZE = 1024;
-	/** Number of bytes to ask for when copying a stream to a file. */
-	private static final int TRANSFER_SIZE = 32768;
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	/**
-	 * @return Count of the number of external calls into this webapp.
-	 */
-	@ManagedMetric(description = "Count of the number of external calls into this webapp.", metricType = COUNTER, category = "throughput")
-	public int getInvocationCount() {
-		return counter.getCount();
-	}
-
-	/**
-	 * @return Current number of runs.
-	 */
-	@ManagedMetric(description = "Current number of runs.", metricType = GAUGE, category = "utilization")
-	public int getCurrentRunCount() {
-		return runStore.listRuns(null, policy).size();
-	}
-
-	/**
-	 * @return Whether to write submitted workflows to the log.
-	 */
-	@ManagedAttribute(description = "Whether to write submitted workflows to the log.")
-	public boolean getLogIncomingWorkflows() {
-		return stateModel.getLogIncomingWorkflows();
-	}
-
-	/**
-	 * @param logIncomingWorkflows
-	 *            Whether to write submitted workflows to the log.
-	 */
-	@ManagedAttribute(description = "Whether to write submitted workflows to the log.")
-	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
-		stateModel.setLogIncomingWorkflows(logIncomingWorkflows);
-	}
-
-	/**
-	 * @return Whether outgoing exceptions should be logged before being
-	 *         converted to responses.
-	 */
-	@ManagedAttribute(description = "Whether outgoing exceptions should be logged before being converted to responses.")
-	public boolean getLogOutgoingExceptions() {
-		return stateModel.getLogOutgoingExceptions();
-	}
-
-	/**
-	 * @param logOutgoing
-	 *            Whether outgoing exceptions should be logged before being
-	 *            converted to responses.
-	 */
-	@ManagedAttribute(description = "Whether outgoing exceptions should be logged before being converted to responses.")
-	public void setLogOutgoingExceptions(boolean logOutgoing) {
-		stateModel.setLogOutgoingExceptions(logOutgoing);
-	}
-
-	/**
-	 * @return Whether to permit any new workflow runs to be created.
-	 */
-	@ManagedAttribute(description = "Whether to permit any new workflow runs to be created; has no effect on existing runs.")
-	public boolean getAllowNewWorkflowRuns() {
-		return stateModel.getAllowNewWorkflowRuns();
-	}
-
-	/**
-	 * @param allowNewWorkflowRuns
-	 *            Whether to permit any new workflow runs to be created.
-	 */
-	@ManagedAttribute(description = "Whether to permit any new workflow runs to be created; has no effect on existing runs.")
-	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
-		stateModel.setAllowNewWorkflowRuns(allowNewWorkflowRuns);
-	}
-
-	/**
-	 * @return The server's version identifier.
-	 */
-	@ManagedAttribute(description = "The installed version of the server.")
-	public String getServerVersion() {
-		return VersionedElement.VERSION + " " + VersionedElement.REVISION + " "
-				+ VersionedElement.TIMESTAMP;
-	}
-
-	@ManagedAttribute(description = "The URIs of the workfows that this server will allow to be instantiated.")
-	public URI[] getPermittedWorkflowURIs() {
-		List<URI> pw = policy.listPermittedWorkflowURIs(null);
-		if (pw == null)
-			return new URI[0];
-		return pw.toArray(new URI[pw.size()]);
-	}
-
-	@ManagedAttribute(description = "The URIs of the workfows that this server will allow to be instantiated.")
-	public void setPermittedWorkflowURIs(URI[] pw) {
-		if (pw == null)
-			policy.setPermittedWorkflowURIs(null, new ArrayList<URI>());
-		else
-			policy.setPermittedWorkflowURIs(null, Arrays.asList(pw));
-	}
-
-	public int getMaxSimultaneousRuns() {
-		Integer limit = policy.getMaxRuns(getPrincipal());
-		if (limit == null)
-			return policy.getMaxRuns();
-		return min(limit.intValue(), policy.getMaxRuns());
-	}
-
-	@Autowired
-	private T2FlowDocumentHandler t2flowHandler;
-
-	public Workflow getWorkflowDocumentFromURI(URI uri)
-			throws WebApplicationException, IOException {
-		URLConnection conn = uri.toURL().openConnection();
-		conn.setRequestProperty("Accept", T2FLOW);
-		conn.connect();
-		// Tricky point: we know the reader part of the handler only cares
-		// about the stream argument.
-		return t2flowHandler.readFrom(null, null, null, null, null,
-				conn.getInputStream());
-	}
-
-	public List<String> getListenerTypes() {
-		return listenerFactory.getSupportedListenerTypes();
-	}
-
-	/**
-	 * @param policy
-	 *            The policy being installed by Spring.
-	 */
-	@Required
-	public void setPolicy(Policy policy) {
-		this.policy = policy;
-	}
-
-	/**
-	 * @param listenerFactory
-	 *            The listener factory being installed by Spring.
-	 */
-	@Required
-	public void setListenerFactory(ListenerFactory listenerFactory) {
-		this.listenerFactory = listenerFactory;
-	}
-
-	/**
-	 * @param runFactory
-	 *            The run factory being installed by Spring.
-	 */
-	@Required
-	public void setRunFactory(RunFactory runFactory) {
-		this.runFactory = runFactory;
-	}
-
-	/**
-	 * @param runStore
-	 *            The run store being installed by Spring.
-	 */
-	@Required
-	public void setRunStore(RunStore runStore) {
-		this.runStore = runStore;
-	}
-
-	/**
-	 * @param stateModel
-	 *            The state model engine being installed by Spring.
-	 */
-	@Required
-	public void setStateModel(ManagementModel stateModel) {
-		this.stateModel = stateModel;
-	}
-
-	/**
-	 * @param mapper
-	 *            The identity mapper being installed by Spring.
-	 */
-	@Required
-	public void setIdMapper(LocalIdentityMapper mapper) {
-		this.idMapper = mapper;
-	}
-
-	/**
-	 * @param counter
-	 *            The object whose job it is to manage the counting of
-	 *            invocations. Installed by Spring.
-	 */
-	@Required
-	public void setInvocationCounter(InvocationCounter counter) {
-		this.counter = counter;
-	}
-
-	/**
-	 * @param webapp
-	 *            The web-app being installed by Spring.
-	 */
-	@Required
-	public void setWebapp(TavernaServerBean webapp) {
-		this.webapp = webapp;
-	}
-
-	/**
-	 * @param fileUtils
-	 *            The file handling utilities.
-	 */
-	@Required
-	public void setFileUtils(FilenameUtils fileUtils) {
-		this.fileUtils = fileUtils;
-	}
-
-	/**
-	 * @param logthem
-	 *            Whether to log failures relating to principals.
-	 */
-	public void setLogGetPrincipalFailures(boolean logthem) {
-		logGetPrincipalFailures = logthem;
-	}
-
-	public Map<String, String> getContentTypeMap() {
-		return contentTypeMap;
-	}
-
-	/**
-	 * Mapping from filename suffixes (e.g., "baclava") to content types.
-	 * 
-	 * @param contentTypeMap
-	 *            The mapping to install.
-	 */
-	@Required
-	public void setContentTypeMap(Map<String, String> contentTypeMap) {
-		this.contentTypeMap = contentTypeMap;
-	}
-
-	@Required
-	public void setCapabilitySource(CapabilityLister capabilitySource) {
-		this.capabilitySource = capabilitySource;
-	}
-
-	/**
-	 * Test whether the current user can do updates to the given run.
-	 * 
-	 * @param run
-	 *            The workflow run to do the test on.
-	 * @throws NoUpdateException
-	 *             If the current user is not permitted to update the run.
-	 */
-	public void permitUpdate(@Nonnull TavernaRun run) throws NoUpdateException {
-		if (isSuperUser()) {
-			accessLog
-					.warn("check for admin powers passed; elevated access rights granted for update");
-			return; // Superusers are fully authorized to access others things
-		}
-		if (getSelfAuthority() != null) {
-			// At this point, must already be accessing self as that is checked
-			// in getRun().
-			return;
-		}
-		policy.permitUpdate(getPrincipal(), run);
-	}
-
-	/**
-	 * Test whether the current user can destroy or control the lifespan of the
-	 * given run.
-	 * 
-	 * @param run
-	 *            The workflow run to do the test on.
-	 * @throws NoDestroyException
-	 *             If the current user is not permitted to destroy the run.
-	 */
-	public void permitDestroy(TavernaRun run) throws NoDestroyException {
-		if (isSuperUser()) {
-			accessLog
-					.warn("check for admin powers passed; elevated access rights granted for destroy");
-			return; // Superusers are fully authorized to access others things
-		}
-		if (getSelfAuthority() != null)
-			throw new NoDestroyException();
-		policy.permitDestroy(getPrincipal(), run);
-	}
-
-	/**
-	 * Gets the identity of the user currently accessing the webapp, which is
-	 * stored in a thread-safe way in the webapp's container's context.
-	 * 
-	 * @return The identity of the user accessing the webapp.
-	 */
-	@Nonnull
-	public UsernamePrincipal getPrincipal() {
-		try {
-			Authentication auth = SecurityContextHolder.getContext()
-					.getAuthentication();
-			if (auth == null || !auth.isAuthenticated()) {
-				if (logGetPrincipalFailures)
-					log.warn("failed to get auth; going with <NOBODY>");
-				return new UsernamePrincipal("<NOBODY>");
-			}
-			return new UsernamePrincipal(auth);
-		} catch (RuntimeException e) {
-			if (logGetPrincipalFailures)
-				log.info("failed to map principal", e);
-			throw e;
-		}
-	}
-
-	private WorkflowSelfAuthority getSelfAuthority() {
-		try {
-			Authentication a = SecurityContextHolder.getContext()
-					.getAuthentication();
-			for (GrantedAuthority ga : a.getAuthorities())
-				if (ga instanceof WorkflowSelfAuthority)
-					return (WorkflowSelfAuthority) ga;
-		} catch (RuntimeException e) {
-		}
-		return null;
-	}
-
-	/**
-	 * Obtain the workflow run with a particular name.
-	 * 
-	 * @param name
-	 *            The name of the run to look up.
-	 * @return A workflow run handle that the current user has at least
-	 *         permission to read.
-	 * @throws UnknownRunException
-	 *             If the workflow run doesn't exist or the current user doesn't
-	 *             have permission to see it.
-	 */
-	@Nonnull
-	public TavernaRun getRun(@Nonnull String name) throws UnknownRunException {
-		if (isSuperUser()) {
-			accessLog
-					.info("check for admin powers passed; elevated access rights granted for read");
-			return runStore.getRun(name);
-		}
-		WorkflowSelfAuthority wsa = getSelfAuthority();
-		if (wsa != null) {
-			if (wsa.getWorkflowID().equals(name))
-				return runStore.getRun(name);
-			throw new UnknownRunException();
-		}
-		return runStore.getRun(getPrincipal(), policy, name);
-	}
-
-	/**
-	 * Construct a listener attached to the given run.
-	 * 
-	 * @param run
-	 *            The workflow run to attach the listener to.
-	 * @param type
-	 *            The name of the type of run to create.
-	 * @param configuration
-	 *            The configuration description to pass into the listener. The
-	 *            format of this string is up to the listener to define.
-	 * @return A handle to the listener which can be used to further configure
-	 *         any properties.
-	 * @throws NoListenerException
-	 *             If the listener type is unrecognized or the configuration is
-	 *             invalid.
-	 * @throws NoUpdateException
-	 *             If the run does not permit the current user to add listeners
-	 *             (or perform other types of update).
-	 */
-	@Nonnull
-	public Listener makeListener(@Nonnull TavernaRun run, @Nonnull String type,
-			@Nonnull String configuration) throws NoListenerException,
-			NoUpdateException {
-		permitUpdate(run);
-		return listenerFactory.makeListener(run, type, configuration);
-	}
-
-	/**
-	 * Obtain a listener that is already attached to a workflow run.
-	 * 
-	 * @param run
-	 *            The workflow run to search.
-	 * @param listenerName
-	 *            The name of the listener to look up.
-	 * @return The listener instance interface.
-	 * @throws NoListenerException
-	 *             If no listener with that name exists.
-	 */
-	@Nonnull
-	public Listener getListener(TavernaRun run, String listenerName)
-			throws NoListenerException {
-		for (Listener l : run.getListeners())
-			if (l.getName().equals(listenerName))
-				return l;
-		throw new NoListenerException();
-	}
-
-	/**
-	 * Obtain a property from a listener that is already attached to a workflow
-	 * run.
-	 * 
-	 * @param runName
-	 *            The ID of the workflow run to search.
-	 * @param listenerName
-	 *            The name of the listener to look up in.
-	 * @param propertyName
-	 *            The name of the property to fetch.
-	 * @return The property value.
-	 * @throws NoListenerException
-	 *             If no listener with that name exists, or no property with
-	 *             that name exists.
-	 * @throws UnknownRunException
-	 *             If no run with that name exists.
-	 */
-	@Nonnull
-	public String getProperty(String runName, String listenerName,
-			String propertyName) throws NoListenerException,
-			UnknownRunException {
-		return getListener(runName, listenerName).getProperty(propertyName);
-	}
-
-	/**
-	 * Obtain a property from a listener that is already attached to a workflow
-	 * run.
-	 * 
-	 * @param run
-	 *            The workflow run to search.
-	 * @param listenerName
-	 *            The name of the listener to look up in.
-	 * @param propertyName
-	 *            The name of the property to fetch.
-	 * @return The property value.
-	 * @throws NoListenerException
-	 *             If no listener with that name exists, or no property with
-	 *             that name exists.
-	 */
-	@Nonnull
-	public String getProperty(TavernaRun run, String listenerName,
-			String propertyName) throws NoListenerException {
-		return getListener(run, listenerName).getProperty(propertyName);
-	}
-
-	/**
-	 * Get the permission description for the given user.
-	 * 
-	 * @param context
-	 *            A security context associated with a particular workflow run.
-	 *            Note that only the owner of a workflow run may get the
-	 *            security context in the first place.
-	 * @param userName
-	 *            The name of the user to look up the permission for.
-	 * @return A permission description.
-	 */
-	@Nonnull
-	public Permission getPermission(@Nonnull TavernaSecurityContext context,
-			@Nonnull String userName) {
-		if (context.getPermittedDestroyers().contains(userName))
-			return Permission.Destroy;
-		if (context.getPermittedUpdaters().contains(userName))
-			return Permission.Update;
-		if (context.getPermittedReaders().contains(userName))
-			return Permission.Read;
-		return Permission.None;
-	}
-
-	/**
-	 * Set the permissions for the given user.
-	 * 
-	 * @param context
-	 *            A security context associated with a particular workflow run.
-	 *            Note that only the owner of a workflow run may get the
-	 *            security context in the first place.
-	 * @param userName
-	 *            The name of the user to set the permission for.
-	 * @param permission
-	 *            The description of the permission to grant. Note that the
-	 *            owner of a workflow run always has the equivalent of
-	 *            {@link Permission#Destroy}; this is always enforced before
-	 *            checking for other permissions.
-	 */
-	public void setPermission(TavernaSecurityContext context, String userName,
-			Permission permission) {
-		Set<String> permSet;
-		boolean doRead = false, doWrite = false, doKill = false;
-
-		switch (permission) {
-		case Destroy:
-			doKill = true;
-		case Update:
-			doWrite = true;
-		case Read:
-			doRead = true;
-		default:
-			break;
-		}
-
-		permSet = context.getPermittedReaders();
-		if (doRead) {
-			if (!permSet.contains(userName)) {
-				permSet = new HashSet<>(permSet);
-				permSet.add(userName);
-				context.setPermittedReaders(permSet);
-			}
-		} else if (permSet.contains(userName)) {
-			permSet = new HashSet<>(permSet);
-			permSet.remove(userName);
-			context.setPermittedReaders(permSet);
-		}
-
-		permSet = context.getPermittedUpdaters();
-		if (doWrite) {
-			if (!permSet.contains(userName)) {
-				permSet = new HashSet<>(permSet);
-				permSet.add(userName);
-				context.setPermittedUpdaters(permSet);
-			}
-		} else if (permSet.contains(userName)) {
-			permSet = new HashSet<>(permSet);
-			permSet.remove(userName);
-			context.setPermittedUpdaters(permSet);
-		}
-
-		permSet = context.getPermittedDestroyers();
-		if (doKill) {
-			if (!permSet.contains(userName)) {
-				permSet = new HashSet<>(permSet);
-				permSet.add(userName);
-				context.setPermittedDestroyers(permSet);
-			}
-		} else if (permSet.contains(userName)) {
-			permSet = new HashSet<>(permSet);
-			permSet.remove(userName);
-			context.setPermittedDestroyers(permSet);
-		}
-	}
-
-	public Map<String, Permission> getPermissionMap(
-			TavernaSecurityContext context) {
-		Map<String, Permission> perm = new HashMap<>();
-		for (String u : context.getPermittedReaders())
-			perm.put(u, Permission.Read);
-		for (String u : context.getPermittedUpdaters())
-			perm.put(u, Permission.Update);
-		for (String u : context.getPermittedDestroyers())
-			perm.put(u, Permission.Destroy);
-		return perm;
-	}
-
-	/**
-	 * Stops a run from being possible to be looked up and destroys it.
-	 * 
-	 * @param runName
-	 *            The name of the run.
-	 * @param run
-	 *            The workflow run. <i>Must</i> correspond to the name.
-	 * @throws NoDestroyException
-	 *             If the user is not permitted to destroy the workflow run.
-	 * @throws UnknownRunException
-	 *             If the run is unknown (e.g., because it is already
-	 *             destroyed).
-	 */
-	public void unregisterRun(@Nonnull String runName, @Nonnull TavernaRun run)
-			throws NoDestroyException, UnknownRunException {
-		if (run == null)
-			run = getRun(runName);
-		permitDestroy(run);
-		runStore.unregisterRun(runName);
-		run.destroy();
-	}
-
-	/**
-	 * Changes the expiry date of a workflow run. The expiry date is when the
-	 * workflow run becomes eligible for automated destruction.
-	 * 
-	 * @param run
-	 *            The handle to the workflow run.
-	 * @param date
-	 *            When the workflow run should be expired.
-	 * @return When the workflow run will actually be expired.
-	 * @throws NoDestroyException
-	 *             If the user is not permitted to destroy the workflow run.
-	 *             (Note that lifespan management requires the ability to
-	 *             destroy.)
-	 */
-	@Nonnull
-	public Date updateExpiry(@Nonnull TavernaRun run, @Nonnull Date date)
-			throws NoDestroyException {
-		permitDestroy(run);
-		run.setExpiry(date);
-		return run.getExpiry();
-	}
-
-	/**
-	 * Manufacture a workflow run instance.
-	 * 
-	 * @param workflow
-	 *            The workflow document (t2flow, scufl2?) to instantiate.
-	 * @return The ID of the created workflow run.
-	 * @throws NoCreateException
-	 *             If the user is not permitted to create workflows.
-	 */
-	public String buildWorkflow(Workflow workflow) throws NoCreateException {
-		UsernamePrincipal p = getPrincipal();
-		if (getSelfAuthority() != null)
-			throw new NoCreateException(
-					"runs may not create workflows on their host server");
-		if (!stateModel.getAllowNewWorkflowRuns())
-			throw new NoCreateException("run creation not currently enabled");
-		try {
-			if (stateModel.getLogIncomingWorkflows()) {
-				log.info(workflow.marshal());
-			}
-		} catch (JAXBException e) {
-			log.warn("problem when logging workflow", e);
-		}
-
-		// Security checks
-		policy.permitCreate(p, workflow);
-		if (idMapper != null && idMapper.getUsernameForPrincipal(p) == null) {
-			log.error("cannot map principal to local user id");
-			throw new NoCreateException(
-					"failed to map security token to local user id");
-		}
-
-		TavernaRun run;
-		try {
-			run = runFactory.create(p, workflow);
-			TavernaSecurityContext c = run.getSecurityContext();
-			c.initializeSecurityFromContext(SecurityContextHolder.getContext());
-			/*
-			 * These next pieces of security initialisation are (hopefully)
-			 * obsolete now that we use Spring Security, but we keep them Just
-			 * In Case.
-			 */
-			boolean doRESTinit = webapp.initObsoleteSOAPSecurity(c);
-			if (doRESTinit)
-				webapp.initObsoleteRESTSecurity(c);
-		} catch (Exception e) {
-			log.error("failed to build workflow run worker", e);
-			throw new NoCreateException("failed to build workflow run worker");
-		}
-
-		return runStore.registerRun(run);
-	}
-
-	private boolean isSuperUser() {
-		try {
-			Authentication auth = SecurityContextHolder.getContext()
-					.getAuthentication();
-			if (auth == null || !auth.isAuthenticated())
-				return false;
-			UserDetails details = (UserDetails) auth.getPrincipal();
-			if (log.isDebugEnabled())
-				log.debug("checking for admin role for user <" + auth.getName()
-						+ "> in collection " + details.getAuthorities());
-			return details.getAuthorities().contains(ADMIN);
-		} catch (ClassCastException e) {
-			return false;
-		}
-	}
-
-	/**
-	 * Get a particular input to a workflow run.
-	 * 
-	 * @param run
-	 *            The workflow run to search.
-	 * @param portName
-	 *            The name of the input.
-	 * @return The handle of the input, or <tt>null</tt> if no such handle
-	 *         exists.
-	 */
-	@Nullable
-	public Input getInput(TavernaRun run, String portName) {
-		for (Input i : run.getInputs())
-			if (i.getName().equals(portName))
-				return i;
-		return null;
-	}
-
-	/**
-	 * Get a listener attached to a run.
-	 * 
-	 * @param runName
-	 *            The name of the run to look up
-	 * @param listenerName
-	 *            The name of the listener.
-	 * @return The handle of the listener.
-	 * @throws NoListenerException
-	 *             If no such listener exists.
-	 * @throws UnknownRunException
-	 *             If no such workflow run exists, or if the user does not have
-	 *             permission to access it.
-	 */
-	public Listener getListener(String runName, String listenerName)
-			throws NoListenerException, UnknownRunException {
-		return getListener(getRun(runName), listenerName);
-	}
-
-	/**
-	 * Given a file, produce a guess at its content type. This uses the content
-	 * type map property, and if that search fails it falls back on the Medsea
-	 * mime type library.
-	 * 
-	 * @param f
-	 *            The file handle.
-	 * @return The content type. If all else fails, produces good old
-	 *         "application/octet-stream".
-	 */
-	@Nonnull
-	public String getEstimatedContentType(@Nonnull File f) {
-		String name = f.getName();
-		for (int idx = name.indexOf('.'); idx != -1; idx = name.indexOf('.',
-				idx + 1)) {
-			String mt = contentTypeMap.get(name.substring(idx + 1));
-			if (mt != null)
-				return mt;
-		}
-		@Nonnull
-		String type = getExtensionMimeTypes(name);
-		if (!type.equals(UNKNOWN_MIME_TYPE))
-			return type;
-		try {
-			return getMimeType(new ByteArrayInputStream(f.getContents(0,
-					SAMPLE_SIZE)));
-		} catch (FilesystemAccessException e) {
-			return type;
-		}
-	}
-
-	public void copyDataToFile(DataHandler handler, File file)
-			throws FilesystemAccessException {
-		try {
-			copyStreamToFile(handler.getInputStream(), file);
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"problem constructing stream from data source", e);
-		}
-	}
-
-	public void copyDataToFile(URI uri, File file)
-			throws MalformedURLException, FilesystemAccessException,
-			IOException {
-		copyStreamToFile(uri.toURL().openStream(), file);
-	}
-
-	public void copyStreamToFile(InputStream stream, File file)
-			throws FilesystemAccessException {
-		String name = file.getFullName();
-		long total = 0;
-		try {
-			byte[] buffer = new byte[TRANSFER_SIZE];
-			boolean first = true;
-			while (true) {
-				int len = stream.read(buffer);
-				if (len < 0)
-					break;
-				total += len;
-				if (log.isDebugEnabled())
-					log.debug("read " + len
-							+ " bytes from source stream (total: " + total
-							+ ") bound for " + name);
-				if (len == buffer.length) {
-					if (first)
-						file.setContents(buffer);
-					else
-						file.appendContents(buffer);
-				} else {
-					byte[] newBuf = new byte[len];
-					System.arraycopy(buffer, 0, newBuf, 0, len);
-					if (first)
-						file.setContents(newBuf);
-					else
-						file.appendContents(newBuf);
-				}
-				first = false;
-			}
-		} catch (IOException exn) {
-			throw new FilesystemAccessException("failed to transfer bytes", exn);
-		}
-	}
-
-	/**
-	 * Build a description of the profiles supported by a workflow. Note that we
-	 * expect the set of profiles to be fairly small.
-	 * 
-	 * @param workflow
-	 *            The workflow to describe the profiles of.
-	 * @return The descriptor (which might be empty).
-	 */
-	public ProfileList getProfileDescriptor(Workflow workflow) {
-		ProfileList result = new ProfileList();
-		String main = workflow.getMainProfileName();
-		for (Profile p : workflow.getProfiles()) {
-			ProfileList.Info i = new ProfileList.Info();
-			i.name = p.getName();
-			if (main != null && main.equals(i.name))
-				i.main = true;
-			result.profile.add(i);
-		}
-		return result;
-	}
-
-	public boolean getAllowStartWorkflowRuns() {
-		return runFactory.isAllowingRunsToStart();
-	}
-
-	/**
-	 * The list of filenames that logs may occupy.
-	 */
-	private static final String[] LOGS = { "logs/detail.log.4",
-			"logs/detail.log.3", "logs/detail.log.2", "logs/detail.log.1",
-			"logs/detail.log" };
-
-	public FileConcatenation getLogs(TavernaRun run) {
-		FileConcatenation fc = new FileConcatenation();
-		for (String name : LOGS) {
-			try {
-				fc.add(fileUtils.getFile(run, name));
-			} catch (FilesystemAccessException | NoDirectoryEntryException e) {
-				// Ignore
-			}
-		}
-		return fc;
-	}
-
-	@Nonnull
-	public List<Capability> getCapabilities() {
-		return capabilitySource.getCapabilities();
-	}
-
-	static final String PROV_BUNDLE = "out.bundle.zip";
-
-	public FileConcatenation getProv(TavernaRun run) {
-		FileConcatenation fc = new FileConcatenation();
-		try {
-			fc.add(fileUtils.getFile(run, PROV_BUNDLE));
-		} catch (FilesystemAccessException | NoDirectoryEntryException e) {
-			// Ignore
-		}
-		return fc;
-	}
-}


[15/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java
deleted file mode 100644
index 42de7d1..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.ws.WebFault;
-
-
-/**
- * Exception that is thrown to indicate that the user is not permitted to
- * destroy something.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoDestroyFault")
-public class NoDestroyException extends NoUpdateException {
-	private static final long serialVersionUID = 6207448533265237933L;
-
-	public NoDestroyException() {
-		super("not permitted to destroy");
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java
deleted file mode 100644
index 32300d1..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.ws.WebFault;
-
-/**
- * Indicates that the file or directory name was not recognized.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoDirectoryEntryFault")
-@SuppressWarnings("serial")
-public class NoDirectoryEntryException extends Exception {
-	public NoDirectoryEntryException(String msg) {
-		super(msg);
-	}
-	public NoDirectoryEntryException(String msg,Exception cause) {
-		super(msg, cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java
deleted file mode 100644
index ef84e9e..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.ws.WebFault;
-
-/**
- * Exception thrown to indicate that no listener by that name exists, or that
- * some other problem with listeners has occurred.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoListenerFault")
-@XmlSeeAlso(BadPropertyValueException.class)
-public class NoListenerException extends Exception {
-	private static final long serialVersionUID = -2550897312787546547L;
-
-	public NoListenerException() {
-		super("no such listener");
-	}
-
-	public NoListenerException(String msg) {
-		super(msg);
-	}
-
-	public NoListenerException(String msg, Throwable t) {
-		super(msg, t);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java
deleted file mode 100644
index 5e972dd..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.ws.WebFault;
-
-/**
- * Exception that is thrown to indicate that the user is not permitted to update
- * something.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoUpdateFault")
-@XmlSeeAlso( { NoCreateException.class, NoDestroyException.class, BadStateChangeException.class })
-public class NoUpdateException extends Exception {
-	private static final long serialVersionUID = 4230987102653846379L;
-
-	public NoUpdateException() {
-		super("not permitted to update");
-	}
-
-	public NoUpdateException(String msg) {
-		super(msg);
-	}
-
-	public NoUpdateException(String string, Throwable e) {
-		super(string, e);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java
deleted file mode 100644
index 29e00b7..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.ws.WebFault;
-
-/**
- * An exception thrown when an operation is attempted which only the owner is
- * permitted to do. Notably, permissions may <i>only</i> be manipulated by the
- * owner.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NotOwnerFault")
-@SuppressWarnings("serial")
-public class NotOwnerException extends Exception {
-	public NotOwnerException() {
-		super("not permitted; not the owner");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java
deleted file mode 100644
index bd34659..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.ws.WebFault;
-
-/**
- * Exception that is thrown to indicate that the state change requested for a
- * run is currently impossible due to excessive server load.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "OverloadedFault")
-public class OverloadedException extends BadStateChangeException {
-	private static final long serialVersionUID = 490826388447601776L;
-
-	public OverloadedException() {
-		super("server too busy; try later please");
-	}
-
-	public OverloadedException(Throwable t) {
-		super("server too busy; try later please", t);
-	}
-
-	public OverloadedException(String msg, Throwable t) {
-		super(msg, t);
-	}
-
-	public OverloadedException(String message) {
-		super(message);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java
deleted file mode 100644
index af717ab..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.ws.WebFault;
-
-/**
- * Exception thrown to indicate that the handle of the run is unknown (or
- * unacceptable to the current user).
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "UnknownRunFault")
-public class UnknownRunException extends Exception {
-	private static final long serialVersionUID = -3028749401786242841L;
-
-	public UnknownRunException() {
-		super("unknown run UUID");
-	}
-
-	public UnknownRunException(Throwable t) {
-		super("implementation problems", t);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java
deleted file mode 100644
index b2284ee..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- */
-/**
- * This package contains the exceptions/faults thrown by Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.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/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java
deleted file mode 100644
index 3031520..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- */
-package org.taverna.server.master.facade;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.MediaType.TEXT_HTML_TYPE;
-import static javax.ws.rs.core.Response.ok;
-
-import java.io.IOException;
-import java.net.URL;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.utils.Contextualizer;
-
-/**
- * This is a simple class that is used to serve up a file (with a simple
- * substitution applied) as the root of the T2Server webapp.
- * 
- * @author Donal Fellows
- */
-@Path("/")
-public class Facade {
-	private Log log = LogFactory.getLog("Taverna.Server.Utils");
-	private String welcome;
-	private Contextualizer contextualizer;
-
-	/**
-	 * Set what resource file to use as the template for the response.
-	 * 
-	 * @param file
-	 *            The file from which to load the data (presumed HTML) to serve
-	 *            up as the root content.
-	 * @throws IOException
-	 *             If the file doesn't exist.
-	 */
-	public void setFile(String file) throws IOException {
-		URL full = Facade.class.getResource(file);
-		log.info("setting " + full + " as source of root page");
-		this.welcome = IOUtils.toString(full);
-	}
-
-	@Required
-	public void setContextualizer(Contextualizer contextualizer) {
-		this.contextualizer = contextualizer;
-	}
-
-	/**
-	 * Serve up some HTML as the root of the service.
-	 * 
-	 * @param ui
-	 *            A reference to how we were accessed by the service.
-	 * @return The response, containing the HTML.
-	 */
-	@GET
-	@Path("{dummy:.*}")
-	@Produces("text/html")
-	public Response get(@Context UriInfo ui) {
-		return ok(contextualizer.contextualize(ui, welcome), TEXT_HTML_TYPE)
-				.build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java
deleted file mode 100644
index 2d8f4ef..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-/**
- * Simple facade used at the top level of the Taverna Server in order to
- * provide an entry splash page.
- */
-package org.taverna.server.master.facade;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java
deleted file mode 100644
index 7a4124d..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- */
-package org.taverna.server.master.factories;
-/*
- * 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.
- */
-
-/**
- * Interface to run factories for the purpose of configuration.
- * 
- * @author Donal Fellows
- */
-public interface ConfigurableRunFactory extends RunFactory {
-	/** Where is the registry? Getter */
-	String getRegistryHost();
-
-	/** Where is the registry? Setter */
-	void setRegistryHost(String host);
-
-	/** Where is the registry? Getter */
-	int getRegistryPort();
-
-	/** Where is the registry? Setter */
-	void setRegistryPort(int port);
-
-	/** How much can be done at once? Getter */
-	int getMaxRuns();
-
-	/** How much can be done at once? Setter */
-	void setMaxRuns(int maxRuns);
-
-	/** How long will things live? Getter */
-	int getDefaultLifetime();
-
-	/** How long will things live? Setter */
-	void setDefaultLifetime(int defaultLifetime);
-
-	/** How often do we probe for info? Getter */
-	int getSleepTime();
-
-	/** How often do we probe for info? Setter */
-	void setSleepTime(int sleepTime);
-
-	/** How long do we allow for actions? Getter */
-	int getWaitSeconds();
-
-	/** How long do we allow for actions? Setter */
-	void setWaitSeconds(int seconds);
-
-	/** How do we start the workflow engine? Getter */
-	String getExecuteWorkflowScript();
-
-	/** How do we start the workflow engine? Setter */
-	void setExecuteWorkflowScript(String executeWorkflowScript);
-
-	/** How do we start the file system access process? Getter */
-	String getServerWorkerJar();
-
-	/** How do we start the file system access process? Setter */
-	void setServerWorkerJar(String serverWorkerJar);
-
-	/**
-	 * How do we start the file system access process? Extra arguments to pass.
-	 * Getter
-	 */
-	String[] getExtraArguments();
-
-	/**
-	 * How do we start the file system access process? Extra arguments to pass.
-	 * Setter
-	 */
-	void setExtraArguments(String[] firstArguments);
-
-	/** Where is Java? Getter */
-	String getJavaBinary();
-
-	/** Where is Java? Setter */
-	void setJavaBinary(String javaBinary);
-
-	/** Where do we get passwords from? Getter */
-	String getPasswordFile();
-
-	/** Where do we get passwords from? Setter */
-	void setPasswordFile(String newValue);
-
-	/** How do we switch users? Getter */
-	String getServerForkerJar();
-
-	/** How do we switch users? Setter */
-	void setServerForkerJar(String newValue);
-
-	/** How many runs have there been? */
-	int getTotalRuns();
-
-	/** How long did the last subprocess startup take? */
-	int getLastStartupCheckCount();
-
-	/** What are the current runs? */
-	String[] getCurrentRunNames();
-
-	/** What is the RMI ID of the factory process? */
-	String getFactoryProcessName();
-
-	/** What was the last observed exit code? */
-	Integer getLastExitCode();
-
-	/** What factory process to use for a particular user? */
-	String[] getFactoryProcessMapping();
-
-	/** How many runs can be operating at once? Setter */
-	void setOperatingLimit(int operatingLimit);
-
-	/** How many runs can be operating at once? Getter */
-	int getOperatingLimit();
-
-	/**
-	 * How many runs are actually operating?
-	 * 
-	 * @throws Exception
-	 *             if anything goes wrong
-	 */
-	int getOperatingCount() throws Exception;
-
-	/** How do we start the RMI registry process? Getter */
-	String getRmiRegistryJar();
-
-	/** How do we start the RMI registry process? Setter */
-	void setRmiRegistryJar(String rmiRegistryJar);
-
-	boolean getGenerateProvenance();
-
-	void setGenerateProvenance(boolean generateProvenance);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java
deleted file mode 100644
index bb83401..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- */
-package org.taverna.server.master.factories;
-/*
- * 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.
- */
-
-import java.util.List;
-
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * How to make event listeners of various types that are attached to a workflow
- * instance.
- * 
- * @author Donal Fellows
- */
-public interface ListenerFactory {
-	/**
-	 * Make an event listener.
-	 * 
-	 * @param run
-	 *            The workflow instance to attach the event listener to.
-	 * @param listenerType
-	 *            The type of event listener to create. Must be one of the
-	 *            strings returned by {@link #getSupportedListenerTypes()}.
-	 * @param configuration
-	 *            A configuration document to pass to the listener.
-	 * @return The event listener that was created.
-	 * @throws NoListenerException
-	 *             If the <b>listenerType</b> is unrecognized or the
-	 *             <b>configuration</b> is bad in some way.
-	 */
-	public Listener makeListener(TavernaRun run, String listenerType,
-			String configuration) throws NoListenerException;
-
-	/**
-	 * What types of listener are supported? Note that we assume that the list
-	 * of types is the same for all users and all workflow instances.
-	 * 
-	 * @return A list of supported listener types.
-	 */
-	public List<String> getSupportedListenerTypes();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java
deleted file mode 100644
index d048f70..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- */
-package org.taverna.server.master.factories;
-/*
- * 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.
- */
-
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * How to construct a Taverna Server Workflow Run.
- * 
- * @author Donal Fellows
- */
-public interface RunFactory {
-	/**
-	 * Make a Taverna Server workflow run that is bound to a particular user
-	 * (the "creator") and able to run a particular workflow.
-	 * 
-	 * @param creator
-	 *            The user creating the workflow instance.
-	 * @param workflow
-	 *            The workflow to instantiate
-	 * @return An object representing the run.
-	 * @throws NoCreateException
-	 *             On failure.
-	 */
-	TavernaRun create(UsernamePrincipal creator, Workflow workflow)
-			throws NoCreateException;
-
-	/**
-	 * Check whether the factory is permitting runs to actually start operating.
-	 * 
-	 * @return Whether a run should start.
-	 */
-	boolean isAllowingRunsToStart();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java
deleted file mode 100644
index 56ba1e2..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-/**
- * These interfaces define the principal way for the <i>factories</i> of
- * worker classes to be invoked.
- */
-package org.taverna.server.master.factories;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java
deleted file mode 100644
index 4fd5312..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- */
-package org.taverna.server.master.identity;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Extracts the local user id from the set of Spring Security authorities
- * granted to the current user. This is done by scanning the set of authorities
- * to see if any of them start with the substring listed in the <tt>prefix</tt>
- * property; the username is the rest of the authority string in that case.
- * 
- * @author Donal Fellows
- */
-public class AuthorityDerivedIDMapper implements LocalIdentityMapper {
-	private String prefix = AUTHORITY_PREFIX;
-
-	public String getPrefix() {
-		return prefix;
-	}
-
-	public void setPrefix(String prefix) {
-		this.prefix = prefix;
-	}
-
-	@Override
-	public String getUsernameForPrincipal(UsernamePrincipal user) {
-		Authentication auth = SecurityContextHolder.getContext()
-				.getAuthentication();
-		if (auth == null || !auth.isAuthenticated())
-			return null;
-		for (GrantedAuthority authority : auth.getAuthorities()) {
-			String token = authority.getAuthority();
-			if (token == null)
-				continue;
-			if (token.startsWith(prefix))
-				return token.substring(prefix.length());
-		}
-		return null;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java
deleted file mode 100644
index f0a6f4c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- */
-package org.taverna.server.master.identity;
-/*
- * 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.
- */
-
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.util.List;
-import java.util.Map.Entry;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * An identity mapper that composes the results from other mappers, using the
- * identity mappers in order until one can provide a non-<tt>null</tt> answer.
- * 
- * @author Donal Fellows.
- */
-public class CompositeIDMapper implements LocalIdentityMapper,
-		ApplicationContextAware {
-	private Log log = getLog("Taverna.Server.IdentityMapper");
-	private List<LocalIdentityMapper> mappers;
-	private ApplicationContext context;
-
-	/**
-	 * @param mappers
-	 *            The list of mappers to delegate to. Order is significant.
-	 */
-	public void setIdentityMappers(List<LocalIdentityMapper> mappers) {
-		this.mappers = mappers;
-	}
-
-	@Override
-	public void setApplicationContext(ApplicationContext applicationContext)
-			throws BeansException {
-		context = applicationContext;
-	}
-
-	@Override
-	public String getUsernameForPrincipal(UsernamePrincipal user) {
-		if (mappers == null)
-			return null;
-		for (LocalIdentityMapper m : mappers) {
-			String u = m.getUsernameForPrincipal(user);
-			if (u == null)
-				continue;
-			for (Entry<String, ? extends LocalIdentityMapper> entry : context
-					.getBeansOfType(m.getClass()).entrySet())
-				if (m == entry.getValue()) {
-					log.info("used " + entry.getKey() + " LIM to map " + user
-							+ " to " + u);
-					break;
-				}
-			return u;
-		}
-		return null;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java
deleted file mode 100644
index bf48fc7..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- */
-package org.taverna.server.master.identity;
-/*
- * 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.
- */
-
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A trivial principal to user mapper that always uses the same ID.
- * @author Donal Fellows
- */
-public class ConstantIDMapper implements LocalIdentityMapper {
-	private String id;
-
-	/**
-	 * Sets what local user ID all users should be mapped to.
-	 * 
-	 * @param id
-	 *            The local user ID.
-	 */
-	public void setConstantId(String id) {
-		this.id = id;
-	}
-
-	@Override
-	public String getUsernameForPrincipal(UsernamePrincipal user) {
-		return id;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java
deleted file mode 100644
index 9d11cfd..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- */
-package org.taverna.server.master.identity;
-/*
- * 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.
- */
-
-import static java.util.regex.Pattern.compile;
-
-import java.security.Principal;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A trivial identity mapper that just uses the name out of the
- * {@link Principal}, or uses a regular expression to extract it from the string
- * representation of the principal.
- * 
- * @author Donal Fellows
- */
-public class NameIDMapper implements LocalIdentityMapper {
-	private Pattern pat;
-
-	/**
-	 * @param regexp
-	 *            The regular expression to use. The first capturing group
-	 *            within the RE will be the result of the extraction.
-	 * @throws PatternSyntaxException
-	 *             If the pattern is invalid.
-	 */
-	public void setRegexp(String regexp) throws PatternSyntaxException {
-		pat = compile(regexp);
-	}
-
-	@Override
-	public String getUsernameForPrincipal(UsernamePrincipal user) {
-		if (pat != null) {
-			Matcher m = pat.matcher(user.toString());
-			if (m.find() && m.groupCount() > 0) {
-				return m.group(1);
-			}
-			return null;
-		}
-		return user.getName();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java
deleted file mode 100644
index dc489ae..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java
+++ /dev/null
@@ -1,294 +0,0 @@
-package org.taverna.server.master.identity;
-/*
- * 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.
- */
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.security.authentication.AccountExpiredException;
-import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.security.authentication.AuthenticationServiceException;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.CredentialsExpiredException;
-import org.springframework.security.authentication.DisabledException;
-import org.springframework.security.authentication.LockedException;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-
-/**
- * A stripped down version of a
- * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider
- * DaoAuthenticationProvider}/
- * {@link org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider
- * AbstractUserDetailsAuthenticationProvider} that avoids much of the overhead
- * associated with that class.
- */
-public class StrippedDownAuthProvider implements AuthenticationProvider {
-	/**
-	 * The plaintext password used to perform
-	 * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when
-	 * the user is not found to avoid SEC-2056.
-	 */
-	private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
-
-	/**
-	 * The password used to perform
-	 * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when
-	 * the user is not found to avoid SEC-2056. This is necessary, because some
-	 * {@link PasswordEncoder} implementations will short circuit if the
-	 * password is not in a valid format.
-	 */
-	private String userNotFoundEncodedPassword;
-	private UserDetailsService userDetailsService;
-	private PasswordEncoder passwordEncoder;
-	private Map<String, AuthCacheEntry> authCache = new HashMap<>();
-	protected final Log logger = LogFactory.getLog(getClass());
-
-	private static class AuthCacheEntry {
-		private String creds;
-		private long timestamp;
-		private static final long VALIDITY = 1000 * 60 * 20;
-		AuthCacheEntry(String credentials) {
-			creds = credentials;
-			timestamp = System.currentTimeMillis();
-		}
-		boolean valid(String password) {
-			return creds.equals(password) && timestamp+VALIDITY > System.currentTimeMillis();
-		}
-	}
-
-	@PerfLogged
-	@Override
-	public Authentication authenticate(Authentication authentication)
-			throws AuthenticationException {
-
-		if (!(authentication instanceof UsernamePasswordAuthenticationToken))
-			throw new IllegalArgumentException(
-					"can only authenticate against username+password");
-		UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
-
-		// Determine username
-		String username = (auth.getPrincipal() == null) ? "NONE_PROVIDED"
-				: auth.getName();
-
-		UserDetails user;
-
-		try {
-			user = retrieveUser(username, auth);
-			if (user == null)
-				throw new IllegalStateException(
-						"retrieveUser returned null - a violation of the interface contract");
-		} catch (UsernameNotFoundException notFound) {
-			if (logger.isDebugEnabled())
-				logger.debug("User '" + username + "' not found", notFound);
-			throw new BadCredentialsException("Bad credentials");
-		}
-
-		// Pre-auth
-		if (!user.isAccountNonLocked())
-			throw new LockedException("User account is locked");
-		if (!user.isEnabled())
-			throw new DisabledException("User account is disabled");
-		if (!user.isAccountNonExpired())
-			throw new AccountExpiredException("User account has expired");
-		Object credentials = auth.getCredentials();
-		if (credentials == null) {
-			logger.debug("Authentication failed: no credentials provided");
-
-			throw new BadCredentialsException("Bad credentials");
-		}
-
-		String providedPassword = credentials.toString();
-		boolean matched = false;
-		synchronized (authCache) {
-			AuthCacheEntry pw = authCache.get(username);
-			if (pw != null && providedPassword != null) {
-				if (pw.valid(providedPassword))
-					matched = true;
-				else
-					authCache.remove(username);
-			}
-		}
-		// Auth
-		if (!matched) {
-			if (!passwordEncoder.matches(providedPassword, user.getPassword())) {
-				logger.debug("Authentication failed: password does not match stored value");
-
-				throw new BadCredentialsException("Bad credentials");
-			}
-			if (providedPassword != null)
-				synchronized (authCache) {
-					authCache.put(username, new AuthCacheEntry(providedPassword));
-				}
-		}
-
-		// Post-auth
-		if (!user.isCredentialsNonExpired())
-			throw new CredentialsExpiredException(
-					"User credentials have expired");
-
-		return createSuccessAuthentication(user, auth, user);
-	}
-
-	@PreDestroy
-	void clearCache() {
-		authCache.clear();
-	}
-
-	/**
-	 * Creates a successful {@link Authentication} object.
-	 * <p>
-	 * Protected so subclasses can override.
-	 * </p>
-	 * <p>
-	 * Subclasses will usually store the original credentials the user supplied
-	 * (not salted or encoded passwords) in the returned
-	 * <code>Authentication</code> object.
-	 * </p>
-	 * 
-	 * @param principal
-	 *            that should be the principal in the returned object (defined
-	 *            by the {@link #isForcePrincipalAsString()} method)
-	 * @param authentication
-	 *            that was presented to the provider for validation
-	 * @param user
-	 *            that was loaded by the implementation
-	 * 
-	 * @return the successful authentication token
-	 */
-	private Authentication createSuccessAuthentication(Object principal,
-			Authentication authentication, UserDetails user) {
-		/*
-		 * Ensure we return the original credentials the user supplied, so
-		 * subsequent attempts are successful even with encoded passwords. Also
-		 * ensure we return the original getDetails(), so that future
-		 * authentication events after cache expiry contain the details
-		 */
-		UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
-				principal, authentication.getCredentials(),
-				user.getAuthorities());
-		result.setDetails(authentication.getDetails());
-
-		return result;
-	}
-
-	@Override
-	public boolean supports(Class<?> authentication) {
-		return UsernamePasswordAuthenticationToken.class
-				.isAssignableFrom(authentication);
-	}
-
-	/**
-	 * Allows subclasses to actually retrieve the <code>UserDetails</code> from
-	 * an implementation-specific location, with the option of throwing an
-	 * <code>AuthenticationException</code> immediately if the presented
-	 * credentials are incorrect (this is especially useful if it is necessary
-	 * to bind to a resource as the user in order to obtain or generate a
-	 * <code>UserDetails</code>).
-	 * <p>
-	 * Subclasses are not required to perform any caching, as the
-	 * <code>AbstractUserDetailsAuthenticationProvider</code> will by default
-	 * cache the <code>UserDetails</code>. The caching of
-	 * <code>UserDetails</code> does present additional complexity as this means
-	 * subsequent requests that rely on the cache will need to still have their
-	 * credentials validated, even if the correctness of credentials was assured
-	 * by subclasses adopting a binding-based strategy in this method.
-	 * Accordingly it is important that subclasses either disable caching (if
-	 * they want to ensure that this method is the only method that is capable
-	 * of authenticating a request, as no <code>UserDetails</code> will ever be
-	 * cached) or ensure subclasses implement
-	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
-	 * to compare the credentials of a cached <code>UserDetails</code> with
-	 * subsequent authentication requests.
-	 * </p>
-	 * <p>
-	 * Most of the time subclasses will not perform credentials inspection in
-	 * this method, instead performing it in
-	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
-	 * so that code related to credentials validation need not be duplicated
-	 * across two methods.
-	 * </p>
-	 * 
-	 * @param username
-	 *            The username to retrieve
-	 * @param authentication
-	 *            The authentication request, which subclasses <em>may</em> need
-	 *            to perform a binding-based retrieval of the
-	 *            <code>UserDetails</code>
-	 * 
-	 * @return the user information (never <code>null</code> - instead an
-	 *         exception should the thrown)
-	 * 
-	 * @throws AuthenticationException
-	 *             if the credentials could not be validated (generally a
-	 *             <code>BadCredentialsException</code>, an
-	 *             <code>AuthenticationServiceException</code> or
-	 *             <code>UsernameNotFoundException</code>)
-	 */
-	private UserDetails retrieveUser(String username,
-			UsernamePasswordAuthenticationToken authentication)
-			throws AuthenticationException {
-		try {
-			return userDetailsService.loadUserByUsername(username);
-		} catch (UsernameNotFoundException notFound) {
-			if (authentication.getCredentials() != null) {
-				String presentedPassword = authentication.getCredentials()
-						.toString();
-				passwordEncoder.matches(presentedPassword,
-						userNotFoundEncodedPassword);
-			}
-			throw notFound;
-		} catch (AuthenticationException e) {
-			throw e;
-		} catch (Exception repositoryProblem) {
-			throw new AuthenticationServiceException(
-					repositoryProblem.getMessage(), repositoryProblem);
-		}
-	}
-
-	/**
-	 * Sets the PasswordEncoder instance to be used to encode and validate
-	 * passwords.
-	 */
-	@Required
-	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
-		if (passwordEncoder == null)
-			throw new IllegalArgumentException("passwordEncoder cannot be null");
-
-		this.passwordEncoder = passwordEncoder;
-		this.userNotFoundEncodedPassword = passwordEncoder
-				.encode(USER_NOT_FOUND_PASSWORD);
-	}
-
-	@Required
-	public void setUserDetailsService(UserDetailsService userDetailsService) {
-		if (userDetailsService == null)
-			throw new IllegalStateException("A UserDetailsService must be set");
-		this.userDetailsService = userDetailsService;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/User.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/User.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/User.java
deleted file mode 100644
index 1fdf2bf..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/User.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- */
-package org.taverna.server.master.identity;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.Query;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-
-/**
- * The representation of a user in the database.
- * <p>
- * A user consists logically of a (non-ordered) tuple of items:
- * <ul>
- * <li>The {@linkplain #getUsername() user name},
- * <li>The {@linkplain #getPassword() user's password} (salted, encoded),
- * <li>Whether the user is {@linkplain #isEnabled() enabled} (i.e., able to log
- * in),
- * <li>Whether the user has {@linkplain #isAdmin() administrative privileges}, and
- * <li>What {@linkplain #getLocalUsername() system (Unix) account} the user's
- * workflows will run as; separation between different users that are mapped to
- * the same system account is nothing like as strongly enforced.
- * </ul>
- * 
- * @author Donal Fellows
- */
-@PersistenceCapable(schema = "USERS", table = "LIST")
-@Query(name = "users", language = "SQL", value = "SELECT id FROM USERS.LIST ORDER BY id", resultClass = String.class)
-@XmlRootElement
-@XmlType(name = "User", propOrder = {})
-@SuppressWarnings("serial")
-public class User implements UserDetails {
-	@XmlElement
-	@Persistent
-	private boolean disabled;
-	@XmlElement(name = "username", required = true)
-	@Persistent(primaryKey = "true")
-	private String id;
-	@XmlElement(name = "password", required = true)
-	@Persistent(column = "password")
-	private String encodedPassword;
-	@XmlElement
-	@Persistent
-	private boolean admin;
-	@XmlElement
-	@Persistent
-	private String localUsername;
-
-	@Override
-	public Collection<GrantedAuthority> getAuthorities() {
-		List<GrantedAuthority> auths = new ArrayList<>();
-		auths.add(new LiteralGrantedAuthority(USER));
-		if (admin)
-			auths.add(new LiteralGrantedAuthority(ADMIN));
-		if (localUsername != null)
-			auths.add(new LiteralGrantedAuthority(AUTHORITY_PREFIX
-					+ localUsername));
-		return auths;
-	}
-
-	@Override
-	public String getPassword() {
-		return encodedPassword;
-	}
-
-	@Override
-	public String getUsername() {
-		return id;
-	}
-
-	@Override
-	public boolean isAccountNonExpired() {
-		return true;
-	}
-
-	@Override
-	public boolean isAccountNonLocked() {
-		return true;
-	}
-
-	@Override
-	public boolean isCredentialsNonExpired() {
-		return true;
-	}
-
-	@Override
-	public boolean isEnabled() {
-		return !disabled;
-	}
-
-	void setDisabled(boolean disabled) {
-		this.disabled = disabled;
-	}
-
-	void setUsername(String username) {
-		this.id = username;
-	}
-
-	void setEncodedPassword(String password) {
-		this.encodedPassword = password;
-	}
-
-	void setAdmin(boolean admin) {
-		this.admin = admin;
-	}
-
-	public boolean isAdmin() {
-		return admin;
-	}
-
-	void setLocalUsername(String localUsername) {
-		this.localUsername = localUsername;
-	}
-
-	public String getLocalUsername() {
-		return localUsername;
-	}
-}
-
-@SuppressWarnings("serial")
-class LiteralGrantedAuthority implements GrantedAuthority {
-	private String auth;
-
-	LiteralGrantedAuthority(String auth) {
-		this.auth = auth;
-	}
-
-	@Override
-	public String getAuthority() {
-		return auth;
-	}
-
-	@Override
-	public String toString() {
-		return "AUTHORITY(" + auth + ")";
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java
deleted file mode 100644
index 3177d5c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- */
-package org.taverna.server.master.identity;
-/*
- * 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.
- */
-
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.jdo.annotations.PersistenceAware;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.dao.DataAccessException;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedOperation;
-import org.springframework.jmx.export.annotation.ManagedOperationParameter;
-import org.springframework.jmx.export.annotation.ManagedOperationParameters;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.core.userdetails.memory.UserAttribute;
-import org.springframework.security.core.userdetails.memory.UserAttributeEditor;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.JDOSupport;
-
-/**
- * The bean class that is responsible for managing the users in the database.
- * 
- * @author Donal Fellows
- */
-@PersistenceAware
-@ManagedResource(objectName = JMX_ROOT + "Users", description = "The user database.")
-public class UserStore extends JDOSupport<User> implements UserDetailsService,
-		UserStoreAPI {
-	/** The logger for the user store. */
-	private transient Log log = getLog("Taverna.Server.UserDB");
-
-	public UserStore() {
-		super(User.class);
-	}
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	private Map<String, BootstrapUserInfo> base = new HashMap<>();
-	private String defLocalUser;
-	private PasswordEncoder encoder;
-	private volatile int epoch;
-
-	/**
-	 * Install the encoder that will be used to turn a plaintext password into
-	 * something that it is safe to store in the database.
-	 * 
-	 * @param encoder
-	 *            The password encoder bean to install.
-	 */
-	public void setEncoder(PasswordEncoder encoder) {
-		this.encoder = encoder;
-	}
-
-	public void setBaselineUserProperties(Properties props) {
-		UserAttributeEditor parser = new UserAttributeEditor();
-
-		for (Object name : props.keySet()) {
-			String username = (String) name;
-			String value = props.getProperty(username);
-
-			// Convert value to a password, enabled setting, and list of granted
-			// authorities
-			parser.setAsText(value);
-
-			UserAttribute attr = (UserAttribute) parser.getValue();
-			if (attr != null && attr.isEnabled())
-				base.put(username, new BootstrapUserInfo(username, attr));
-		}
-	}
-
-	private void installPassword(User u, String password) {
-		u.setEncodedPassword(encoder.encode(password));
-	}
-
-	public void setDefaultLocalUser(String defLocalUser) {
-		this.defLocalUser = defLocalUser;
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> getUsers() {
-		return (List<String>) namedQuery("users").execute();
-	}
-
-	@WithinSingleTransaction
-	@PostConstruct
-	void initDB() {
-		if (base == null || base.isEmpty())
-			log.warn("no baseline user collection");
-		else if (!getUsers().isEmpty())
-			log.info("using existing users from database");
-		else
-			for (String username : base.keySet()) {
-				BootstrapUserInfo ud = base.get(username);
-				if (ud == null)
-					continue;
-				User u = ud.get(encoder);
-				if (u == null)
-					continue;
-				log.info("bootstrapping user " + username + " in the database");
-				persist(u);
-			}
-		base = null;
-		epoch++;
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedAttribute(description = "The list of server accounts known about.", currencyTimeLimit = 30)
-	public List<String> getUserNames() {
-		return getUsers();
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	public User getUser(String userName) {
-		return detach(getById(userName));
-	}
-
-	/**
-	 * Get information about a server account.
-	 * 
-	 * @param userName
-	 *            The username to look up.
-	 * @return A description map intended for use by a server admin over JMX.
-	 */
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Get information about a server account.")
-	@ManagedOperationParameters(@ManagedOperationParameter(name = "userName", description = "The username to look up."))
-	public Map<String, String> getUserInfo(String userName) {
-		User u = getById(userName);
-		Map<String, String> info = new HashMap<>();
-		info.put("name", u.getUsername());
-		info.put("admin", u.isAdmin() ? "yes" : "no");
-		info.put("enabled", u.isEnabled() ? "yes" : "no");
-		info.put("localID", u.getLocalUsername());
-		return info;
-	}
-
-	/**
-	 * Get a list of all the users in the database.
-	 * 
-	 * @return A list of user details, <i>copied</i> out of the database.
-	 */
-	@PerfLogged
-	@WithinSingleTransaction
-	public List<UserDetails> listUsers() {
-		ArrayList<UserDetails> result = new ArrayList<>();
-		for (String id : getUsers())
-			result.add(detach(getById(id)));
-		return result;
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Create a new user account; the account will be disabled and "
-			+ "non-administrative by default. Does not create any underlying system account.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to create."),
-			@ManagedOperationParameter(name = "password", description = "The password to use."),
-			@ManagedOperationParameter(name = "coupleLocalUsername", description = "Whether to set the local user name to the 'main' one.") })
-	public void addUser(String username, String password,
-			boolean coupleLocalUsername) {
-		if (username.matches(".*[^a-zA-Z0-9].*"))
-			throw new IllegalArgumentException(
-					"bad user name; must be pure alphanumeric");
-		if (getById(username) != null)
-			throw new IllegalArgumentException("user name already exists");
-		User u = new User();
-		u.setDisabled(true);
-		u.setAdmin(false);
-		u.setUsername(username);
-		installPassword(u, password);
-		if (coupleLocalUsername)
-			u.setLocalUsername(username);
-		else
-			u.setLocalUsername(defLocalUser);
-		log.info("creating user for " + username);
-		persist(u);
-		epoch++;
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Set or clear whether this account is enabled. "
-			+ "Disabled accounts cannot be used to log in.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
-			@ManagedOperationParameter(name = "enabled", description = "Whether to enable the account.") })
-	public void setUserEnabled(String username, boolean enabled) {
-		User u = getById(username);
-		if (u != null) {
-			u.setDisabled(!enabled);
-			log.info((enabled ? "enabling" : "disabling") + " user " + username);
-			epoch++;
-		}
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Set or clear the mark on an account that indicates "
-			+ "that it has administrative privileges.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
-			@ManagedOperationParameter(name = "admin", description = "Whether the account has admin privileges.") })
-	public void setUserAdmin(String username, boolean admin) {
-		User u = getById(username);
-		if (u != null) {
-			u.setAdmin(admin);
-			log.info((admin ? "enabling" : "disabling") + " user " + username
-					+ " admin status");
-			epoch++;
-		}
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Change the password for an account.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
-			@ManagedOperationParameter(name = "password", description = "The new password to use.") })
-	public void setUserPassword(String username, String password) {
-		User u = getById(username);
-		if (u != null) {
-			installPassword(u, password);
-			log.info("changing password for user " + username);
-			epoch++;
-		}
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Change what local system account to use for a server account.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
-			@ManagedOperationParameter(name = "password", description = "The new local user account use.") })
-	public void setUserLocalUser(String username, String localUsername) {
-		User u = getById(username);
-		if (u != null) {
-			u.setLocalUsername(localUsername);
-			log.info("mapping user " + username + " to local account "
-					+ localUsername);
-			epoch++;
-		}
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Delete a server account. The underlying "
-			+ "system account is not modified.")
-	@ManagedOperationParameters(@ManagedOperationParameter(name = "username", description = "The username to delete."))
-	public void deleteUser(String username) {
-		delete(getById(username));
-		log.info("deleting user " + username);
-		epoch++;
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	public UserDetails loadUserByUsername(String username)
-			throws UsernameNotFoundException, DataAccessException {
-		User u;
-		if (base != null) {
-			log.warn("bootstrap user store still installed!");
-			BootstrapUserInfo ud = base.get(username);
-			if (ud != null) {
-				log.warn("retrieved production credentials for " + username
-						+ " from bootstrap store");
-				u = ud.get(encoder);
-				if (u != null)
-					return u;
-			}
-		}
-		try {
-			u = detach(getById(username));
-		} catch (NullPointerException npe) {
-			throw new UsernameNotFoundException("who are you?");
-		} catch (Exception ex) {
-			throw new UsernameNotFoundException("who are you?", ex);
-		}
-		if (u != null)
-			return u;
-		throw new UsernameNotFoundException("who are you?");
-	}
-
-	int getEpoch() {
-		return epoch;
-	}
-
-	public static class CachedUserStore implements UserDetailsService {
-		private int epoch;
-		private Map<String, UserDetails> cache = new HashMap<>();
-		private UserStore realStore;
-
-		@Required
-		public void setRealStore(UserStore store) {
-			this.realStore = store;
-		}
-
-		@Override
-		@PerfLogged
-		public UserDetails loadUserByUsername(String username) {
-			int epoch = realStore.getEpoch();
-			UserDetails details;
-			synchronized (cache) {
-				if (epoch != this.epoch) {
-					cache.clear();
-					this.epoch = epoch;
-					details = null;
-				} else
-					details = cache.get(username);
-			}
-			if (details == null) {
-				details = realStore.loadUserByUsername(username);
-				synchronized (cache) {
-					cache.put(username, details);
-				}
-			}
-			return details;
-		}
-	}
-
-	private static class BootstrapUserInfo {
-		private String user;
-		private String pass;
-		private Collection<GrantedAuthority> auth;
-
-		BootstrapUserInfo(String username, UserAttribute attr) {
-			user = username;
-			pass = attr.getPassword();
-			auth = attr.getAuthorities();
-		}
-
-		User get(PasswordEncoder encoder) {
-			User u = new User();
-			boolean realUser = false;
-			for (GrantedAuthority ga : auth) {
-				String a = ga.getAuthority();
-				if (a.startsWith(AUTHORITY_PREFIX))
-					u.setLocalUsername(a.substring(AUTHORITY_PREFIX.length()));
-				else if (a.equals(USER))
-					realUser = true;
-				else if (a.equals(ADMIN))
-					u.setAdmin(true);
-			}
-			if (!realUser)
-				return null;
-			u.setUsername(user);
-			u.setEncodedPassword(encoder.encode(pass));
-			u.setDisabled(false);
-			return u;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java
deleted file mode 100644
index c4caf3c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package org.taverna.server.master.identity;
-/*
- * 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.
- */
-
-import java.util.List;
-
-/**
- * The API that is exposed by the DAO that exposes user management.
- * 
- * @author Donal Fellows
- * @see User
- */
-public interface UserStoreAPI {
-	/**
-	 * List the currently-known account names.
-	 * 
-	 * @return A list of users in the database. Note that this is a snapshot.
-	 */
-	List<String> getUserNames();
-
-	/**
-	 * Get a particular user's description.
-	 * 
-	 * @param userName
-	 *            The username to look up.
-	 * @return A <i>copy</i> of the user description.
-	 */
-	User getUser(String userName);
-
-	/**
-	 * Create a new user account; the account will be disabled and
-	 * non-administrative by default. Does not create any underlying system
-	 * account.
-	 * 
-	 * @param username
-	 *            The username to create.
-	 * @param password
-	 *            The password to use.
-	 * @param coupleLocalUsername
-	 *            Whether to set the local user name to the 'main' one.
-	 */
-	void addUser(String username, String password, boolean coupleLocalUsername);
-
-	/**
-	 * Set or clear whether this account is enabled. Disabled accounts cannot be
-	 * used to log in.
-	 * 
-	 * @param username
-	 *            The username to adjust.
-	 * @param enabled
-	 *            Whether to enable the account.
-	 */
-	void setUserEnabled(String username, boolean enabled);
-
-	/**
-	 * Set or clear the mark on an account that indicates that it has
-	 * administrative privileges.
-	 * 
-	 * @param username
-	 *            The username to adjust.
-	 * @param admin
-	 *            Whether the account has admin privileges.
-	 */
-	void setUserAdmin(String username, boolean admin);
-
-	/**
-	 * Change the password for an account.
-	 * 
-	 * @param username
-	 *            The username to adjust.
-	 * @param password
-	 *            The new password to use.
-	 */
-	void setUserPassword(String username, String password);
-
-	/**
-	 * Change what local system account to use for a server account.
-	 * 
-	 * @param username
-	 *            The username to adjust.
-	 * @param localUsername
-	 *            The new local user account use.
-	 */
-	void setUserLocalUser(String username, String localUsername);
-
-	/**
-	 * Delete a server account. The underlying system account is not modified.
-	 * 
-	 * @param username
-	 *            The username to delete.
-	 */
-	void deleteUser(String username);
-}


[33/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenersREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenersREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenersREST.java
new file mode 100644
index 0000000..3cc0d73
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenersREST.java
@@ -0,0 +1,106 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.taverna.server.master.api.ListenersBean;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.ListenerDefinition;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful interface to a single workflow run's event listeners.
+ * 
+ * @author Donal Fellows
+ */
+abstract class ListenersREST implements TavernaServerListenersREST,
+		ListenersBean {
+	private TavernaRun run;
+	private TavernaServerSupport support;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	public ListenersREST connect(TavernaRun run) {
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response addListener(ListenerDefinition typeAndConfiguration,
+			UriInfo ui) throws NoUpdateException, NoListenerException {
+		String name = support.makeListener(run, typeAndConfiguration.type,
+				typeAndConfiguration.configuration).getName();
+		return created(secure(ui).path("{listenerName}").build(name)).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public TavernaServerListenerREST getListener(String name)
+			throws NoListenerException {
+		Listener l = support.getListener(run, name);
+		if (l == null)
+			throw new NoListenerException();
+		return makeListenerInterface().connect(l, run);
+	}
+
+	@Nonnull
+	protected abstract SingleListenerREST makeListenerInterface();
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Listeners getDescription(UriInfo ui) {
+		List<ListenerDescription> result = new ArrayList<>();
+		UriBuilder ub = secure(ui).path("{name}");
+		for (Listener l : run.getListeners())
+			result.add(new ListenerDescription(l,
+					fromUri(ub.build(l.getName()))));
+		return new Listeners(result, ub);
+	}
+
+	@Override
+	@CallCounted
+	public Response listenersOptions() {
+		return opt();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ManagementState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ManagementState.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ManagementState.java
new file mode 100644
index 0000000..c65a334
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ManagementState.java
@@ -0,0 +1,228 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import javax.annotation.PostConstruct;
+import javax.jdo.Query;
+import javax.jdo.annotations.PersistenceAware;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.PrimaryKey;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.ManagementModel;
+import org.taverna.server.master.utils.JDOSupport;
+
+/** The persistent, manageable state of the Taverna Server web application. */
+@PersistenceAware
+class ManagementState extends JDOSupport<WebappState> implements
+		ManagementModel {
+	public ManagementState() {
+		super(WebappState.class);
+	}
+
+	/** Whether we should log all workflows sent to us. */
+	private boolean logIncomingWorkflows = false;
+
+	/** Whether we allow the creation of new workflow runs. */
+	private boolean allowNewWorkflowRuns = true;
+
+	/**
+	 * Whether outgoing exceptions should be logged before being converted to
+	 * responses.
+	 */
+	private boolean logOutgoingExceptions = false;
+
+	/**
+	 * The file that all usage records should be appended to, or <tt>null</tt>
+	 * if they should be just dropped.
+	 */
+	private String usageRecordLogFile = null;
+
+	@Override
+	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
+		this.logIncomingWorkflows = logIncomingWorkflows;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public boolean getLogIncomingWorkflows() {
+		self.load();
+		return logIncomingWorkflows;
+	}
+
+	@Override
+	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
+		this.allowNewWorkflowRuns = allowNewWorkflowRuns;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public boolean getAllowNewWorkflowRuns() {
+		self.load();
+		return allowNewWorkflowRuns;
+	}
+
+	@Override
+	public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
+		this.logOutgoingExceptions = logOutgoingExceptions;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public boolean getLogOutgoingExceptions() {
+		self.load();
+		return logOutgoingExceptions || true;
+	}
+
+	@Override
+	public String getUsageRecordLogFile() {
+		self.load();
+		return usageRecordLogFile;
+	}
+
+	@Override
+	public void setUsageRecordLogFile(String usageRecordLogFile) {
+		this.usageRecordLogFile = usageRecordLogFile;
+		if (loadedState)
+			self.store();
+	}
+
+	private static final int KEY = 42; // whatever
+
+	private WebappState get() {
+		Query<WebappState> q = query("id == " + KEY);
+		q.setUnique(true);
+		return q.executeUnique();
+	}
+
+	private boolean loadedState;
+	private ManagementState self;
+
+	@Required
+	public void setSelf(ManagementState self) {
+		this.self = self;
+	}
+
+	@PostConstruct
+	@WithinSingleTransaction
+	public void load() {
+		if (loadedState || !isPersistent())
+			return;
+		WebappState state = get();
+		if (state == null)
+			return;
+		allowNewWorkflowRuns = state.getAllowNewWorkflowRuns();
+		logIncomingWorkflows = state.getLogIncomingWorkflows();
+		logOutgoingExceptions = state.getLogOutgoingExceptions();
+		usageRecordLogFile = state.getUsageRecordLogFile();
+		loadedState = true;
+	}
+
+	@WithinSingleTransaction
+	public void store() {
+		if (!isPersistent())
+			return;
+		WebappState state = get();
+		if (state == null) {
+			state = new WebappState();
+			// save state
+			state.id = KEY; // whatever...
+			state = persist(state);
+		}
+		state.setAllowNewWorkflowRuns(allowNewWorkflowRuns);
+		state.setLogIncomingWorkflows(logIncomingWorkflows);
+		state.setLogOutgoingExceptions(logOutgoingExceptions);
+		state.setUsageRecordLogFile(usageRecordLogFile);
+		loadedState = true;
+	}
+}
+
+// WARNING! If you change the name of this class, update persistence.xml as
+// well!
+@PersistenceCapable(table = "MANAGEMENTSTATE__WEBAPPSTATE")
+class WebappState implements ManagementModel {
+	public WebappState() {
+	}
+
+	@PrimaryKey
+	protected int id;
+
+	/** Whether we should log all workflows sent to us. */
+	@Persistent
+	private boolean logIncomingWorkflows;
+
+	/** Whether we allow the creation of new workflow runs. */
+	@Persistent
+	private boolean allowNewWorkflowRuns;
+
+	/**
+	 * Whether outgoing exceptions should be logged before being converted to
+	 * responses.
+	 */
+	@Persistent
+	private boolean logOutgoingExceptions;
+
+	/** Where to write usage records. */
+	@Persistent
+	private String usageRecordLogFile;
+
+	@Override
+	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
+		this.logIncomingWorkflows = logIncomingWorkflows;
+	}
+
+	@Override
+	public boolean getLogIncomingWorkflows() {
+		return logIncomingWorkflows;
+	}
+
+	@Override
+	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
+		this.allowNewWorkflowRuns = allowNewWorkflowRuns;
+	}
+
+	@Override
+	public boolean getAllowNewWorkflowRuns() {
+		return allowNewWorkflowRuns;
+	}
+
+	@Override
+	public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
+		this.logOutgoingExceptions = logOutgoingExceptions;
+	}
+
+	@Override
+	public boolean getLogOutgoingExceptions() {
+		return logOutgoingExceptions;
+	}
+
+	@Override
+	public String getUsageRecordLogFile() {
+		return usageRecordLogFile;
+	}
+
+	@Override
+	public void setUsageRecordLogFile(String usageRecordLogFile) {
+		this.usageRecordLogFile = usageRecordLogFile;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunREST.java
new file mode 100644
index 0000000..a04de46
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunREST.java
@@ -0,0 +1,512 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static javax.ws.rs.core.Response.noContent;
+import static javax.ws.rs.core.Response.ok;
+import static javax.ws.rs.core.Response.status;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.joda.time.format.ISODateTimeFormat.dateTime;
+import static org.joda.time.format.ISODateTimeFormat.dateTimeParser;
+import static org.taverna.server.master.common.Roles.SELF;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.common.Status.Initialized;
+import static org.taverna.server.master.common.Status.Operating;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.util.Date;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.logging.Log;
+import org.joda.time.DateTime;
+import org.apache.taverna.server.usagerecord.JobUsageRecord;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.RunBean;
+import org.taverna.server.master.common.ProfileList;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.exceptions.NotOwnerException;
+import org.taverna.server.master.exceptions.OverloadedException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.rest.InteractionFeedREST;
+import org.taverna.server.master.rest.TavernaServerInputREST;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.taverna.server.master.rest.TavernaServerRunREST;
+import org.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.taverna.server.port_description.OutputDescription;
+
+/**
+ * RESTful interface to a single workflow run.
+ * 
+ * @author Donal Fellows
+ */
+abstract class RunREST implements TavernaServerRunREST, RunBean {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private String runName;
+	private TavernaRun run;
+	private TavernaServerSupport support;
+	private ContentsDescriptorBuilder cdBuilder;
+
+	@Override
+	@Required
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	@Required
+	public void setCdBuilder(ContentsDescriptorBuilder cdBuilder) {
+		this.cdBuilder = cdBuilder;
+	}
+
+	@Override
+	public void setRunName(String runName) {
+		this.runName = runName;
+	}
+
+	@Override
+	public void setRun(TavernaRun run) {
+		this.run = run;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public RunDescription getDescription(UriInfo ui) {
+		return new RunDescription(run, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response destroy() throws NoUpdateException {
+		try {
+			support.unregisterRun(runName, run);
+		} catch (UnknownRunException e) {
+			log.fatal("can't happen", e);
+		}
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public TavernaServerListenersREST getListeners() {
+		return makeListenersInterface().connect(run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public TavernaServerSecurityREST getSecurity() throws NotOwnerException {
+		TavernaSecurityContext secContext = run.getSecurityContext();
+		if (!support.getPrincipal().equals(secContext.getOwner()))
+			throw new NotOwnerException();
+
+		// context.getBean("run.security", run, secContext);
+		return makeSecurityInterface().connect(secContext, run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getExpiryTime() {
+		return dateTime().print(new DateTime(run.getExpiry()));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getCreateTime() {
+		return dateTime().print(new DateTime(run.getCreationTimestamp()));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getFinishTime() {
+		Date f = run.getFinishTimestamp();
+		return f == null ? "" : dateTime().print(new DateTime(f));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getStartTime() {
+		Date f = run.getStartTimestamp();
+		return f == null ? "" : dateTime().print(new DateTime(f));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getStatus() {
+		return run.getStatus().toString();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Workflow getWorkflow() {
+		return run.getWorkflow();
+	}
+
+	@Override
+	@CallCounted
+	public String getMainProfileName() {
+		String name = run.getWorkflow().getMainProfileName();
+		return (name == null ? "" : name);
+	}
+
+	@Override
+	@CallCounted
+	public ProfileList getProfiles() {
+		return support.getProfileDescriptor(run.getWorkflow());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public DirectoryREST getWorkingDirectory() {
+		return makeDirectoryInterface().connect(run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String setExpiryTime(String expiry) throws NoUpdateException,
+			IllegalArgumentException {
+		DateTime wanted = dateTimeParser().parseDateTime(expiry.trim());
+		Date achieved = support.updateExpiry(run, wanted.toDate());
+		return dateTime().print(new DateTime(achieved));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response setStatus(String status) throws NoUpdateException {
+		Status newStatus = Status.valueOf(status.trim());
+		support.permitUpdate(run);
+		if (newStatus == Operating && run.getStatus() == Initialized) {
+			if (!support.getAllowStartWorkflowRuns())
+				throw new OverloadedException();
+			String issue = run.setStatus(newStatus);
+			if (issue == null)
+				issue = "starting run...";
+			return status(202).entity(issue).type("text/plain").build();
+		}
+		run.setStatus(newStatus); // Ignore the result
+		return ok(run.getStatus().toString()).type("text/plain").build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public TavernaServerInputREST getInputs(UriInfo ui) {
+		return makeInputInterface().connect(run, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getOutputFile() {
+		String o = run.getOutputBaclavaFile();
+		return o == null ? "" : o;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String setOutputFile(String filename) throws NoUpdateException,
+			FilesystemAccessException, BadStateChangeException {
+		support.permitUpdate(run);
+		if (filename != null && filename.length() == 0)
+			filename = null;
+		run.setOutputBaclavaFile(filename);
+		String o = run.getOutputBaclavaFile();
+		return o == null ? "" : o;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public OutputDescription getOutputDescription(UriInfo ui)
+			throws BadStateChangeException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		if (run.getStatus() == Initialized)
+			throw new BadStateChangeException(
+					"may not get output description in initial state");
+		return cdBuilder.makeOutputDescriptor(run, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public InteractionFeedREST getInteractionFeed() {
+		return makeInteractionFeed().connect(run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getName() {
+		return run.getName();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String setName(String name) throws NoUpdateException {
+		support.permitUpdate(run);
+		run.setName(name);
+		return run.getName();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getStdout() throws NoListenerException {
+		return support.getProperty(run, "io", "stdout");
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getStderr() throws NoListenerException {
+		return support.getProperty(run, "io", "stderr");
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response getUsage() throws NoListenerException, JAXBException {
+		String ur = support.getProperty(run, "io", "usageRecord");
+		if (ur.isEmpty())
+			return noContent().build();
+		return ok(JobUsageRecord.unmarshal(ur), APPLICATION_XML).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response getLogContents() {
+		FileConcatenation fc = support.getLogs(run);
+		if (fc.isEmpty())
+			return Response.noContent().build();
+		return Response.ok(fc, TEXT_PLAIN).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response getRunBundle() {
+		FileConcatenation fc = support.getProv(run);
+		if (fc.isEmpty())
+			return Response.status(404).entity("no provenance currently available").build();
+		return Response.ok(fc, "application/vnd.wf4ever.robundle+zip").build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public boolean getGenerateProvenance() {
+		return run.getGenerateProvenance();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public boolean setGenerateProvenance(boolean newValue) throws NoUpdateException {
+		support.permitUpdate(run);
+		run.setGenerateProvenance(newValue);
+		return run.getGenerateProvenance();
+	}
+
+	/**
+	 * Construct a RESTful interface to a run's filestore.
+	 * 
+	 * @return The handle to the interface, as decorated by Spring.
+	 */
+	protected abstract DirectoryREST makeDirectoryInterface();
+
+	/**
+	 * Construct a RESTful interface to a run's input descriptors.
+	 * 
+	 * @return The handle to the interface, as decorated by Spring.
+	 */
+	protected abstract InputREST makeInputInterface();
+
+	/**
+	 * Construct a RESTful interface to a run's listeners.
+	 * 
+	 * @return The handle to the interface, as decorated by Spring.
+	 */
+	protected abstract ListenersREST makeListenersInterface();
+
+	/**
+	 * Construct a RESTful interface to a run's security.
+	 * 
+	 * @return The handle to the interface, as decorated by Spring.
+	 */
+	protected abstract RunSecurityREST makeSecurityInterface();
+
+	/**
+	 * Construct a RESTful interface to a run's interaction feed.
+	 * 
+	 * @return The handle to the interaface, as decorated by Spring.
+	 */
+	protected abstract InteractionFeed makeInteractionFeed();
+
+	@Override
+	@CallCounted
+	public Response runOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response workflowOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response profileOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response expiryOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response createTimeOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response startTimeOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response finishTimeOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response statusOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response outputOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response nameOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response stdoutOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response stderrOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response usageOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response logOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response runBundleOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response generateProvenanceOptions() {
+		return opt("PUT");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunSecurityREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunSecurityREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunSecurityREST.java
new file mode 100644
index 0000000..9dc69d7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/RunSecurityREST.java
@@ -0,0 +1,316 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static java.util.UUID.randomUUID;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.Response.noContent;
+import static org.taverna.server.master.common.Status.Initialized;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.taverna.server.master.api.SecurityBean;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Permission;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoCredentialException;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful interface to a single workflow run's security settings.
+ * 
+ * @author Donal Fellows
+ */
+class RunSecurityREST implements TavernaServerSecurityREST, SecurityBean {
+	private TavernaServerSupport support;
+	private TavernaSecurityContext context;
+	private TavernaRun run;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	public RunSecurityREST connect(TavernaSecurityContext context,
+			TavernaRun run) {
+		this.context = context;
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Descriptor describe(UriInfo ui) {
+		return new Descriptor(secure(ui).path("{element}"), context.getOwner()
+				.getName(), context.getCredentials(), context.getTrusted());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String getOwner() {
+		return context.getOwner().getName();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public CredentialList listCredentials() {
+		return new CredentialList(context.getCredentials());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public CredentialHolder getParticularCredential(String id)
+			throws NoCredentialException {
+		for (Credential c : context.getCredentials())
+			if (c.id.equals(id))
+				return new CredentialHolder(c);
+		throw new NoCredentialException();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public CredentialHolder setParticularCredential(String id,
+			CredentialHolder cred, UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		Credential c = cred.credential;
+		c.id = id;
+		c.href = ui.getAbsolutePath().toString();
+		context.validateCredential(c);
+		context.deleteCredential(c);
+		context.addCredential(c);
+		return new CredentialHolder(c);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response addCredential(CredentialHolder cred, UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		Credential c = cred.credential;
+		c.id = randomUUID().toString();
+		URI uri = secure(ui).path("{id}").build(c.id);
+		c.href = uri.toString();
+		context.validateCredential(c);
+		context.addCredential(c);
+		return created(uri).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deleteAllCredentials(UriInfo ui)
+			throws BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		for (Credential c : context.getCredentials())
+			context.deleteCredential(c);
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deleteCredential(String id, UriInfo ui)
+			throws BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		context.deleteCredential(new Credential.Dummy(id));
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public TrustList listTrusted() {
+		return new TrustList(context.getTrusted());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Trust getParticularTrust(String id) throws NoCredentialException {
+		for (Trust t : context.getTrusted())
+			if (t.id.equals(id))
+				return t;
+		throw new NoCredentialException();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Trust setParticularTrust(String id, Trust t, UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		t.id = id;
+		t.href = ui.getAbsolutePath().toString();
+		context.validateTrusted(t);
+		context.deleteTrusted(t);
+		context.addTrusted(t);
+		return t;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response addTrust(Trust t, UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		t.id = randomUUID().toString();
+		URI uri = secure(ui).path("{id}").build(t.id);
+		t.href = uri.toString();
+		context.validateTrusted(t);
+		context.addTrusted(t);
+		return created(uri).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deleteAllTrusts(UriInfo ui) throws BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		for (Trust t : context.getTrusted())
+			context.deleteTrusted(t);
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deleteTrust(String id, UriInfo ui)
+			throws BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		Trust toDelete = new Trust();
+		toDelete.id = id;
+		context.deleteTrusted(toDelete);
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public PermissionsDescription describePermissions(UriInfo ui) {
+		Map<String, Permission> perm = support.getPermissionMap(context);
+		return new PermissionsDescription(secure(ui).path("{id}"), perm);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Permission describePermission(String id) {
+		return support.getPermission(context, id);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Permission setPermission(String id, Permission perm) {
+		support.setPermission(context, id, perm);
+		return support.getPermission(context, id);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deletePermission(String id, UriInfo ui) {
+		support.setPermission(context, id, Permission.None);
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response makePermission(PermissionDescription desc, UriInfo ui) {
+		support.setPermission(context, desc.userName, desc.permission);
+		return created(secure(ui).path("{user}").build(desc.userName)).build();
+	}
+
+	@Override
+	@CallCounted
+	public Response descriptionOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response ownerOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response credentialsOptions() {
+		return opt("POST", "DELETE");
+	}
+
+	@Override
+	@CallCounted
+	public Response credentialOptions(String id) {
+		return opt("PUT", "DELETE");
+	}
+
+	@Override
+	@CallCounted
+	public Response trustsOptions() {
+		return opt("POST", "DELETE");
+	}
+
+	@Override
+	@CallCounted
+	public Response trustOptions(String id) {
+		return opt("PUT", "DELETE");
+	}
+
+	@Override
+	@CallCounted
+	public Response permissionsOptions() {
+		return opt("POST");
+	}
+
+	@Override
+	@CallCounted
+	public Response permissionOptions(String id) {
+		return opt("PUT", "DELETE");
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/SingleListenerREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/SingleListenerREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/SingleListenerREST.java
new file mode 100644
index 0000000..2c841cc
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/SingleListenerREST.java
@@ -0,0 +1,110 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static java.util.Arrays.asList;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.taverna.server.master.api.OneListenerBean;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
+import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful interface to a single listener attached to a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+abstract class SingleListenerREST implements TavernaServerListenerREST,
+		OneListenerBean {
+	private Listener listen;
+	private TavernaRun run;
+
+	@Override
+	public SingleListenerREST connect(Listener listen, TavernaRun run) {
+		this.listen = listen;
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String getConfiguration() {
+		return listen.getConfiguration();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public ListenerDescription getDescription(UriInfo ui) {
+		return new ListenerDescription(listen, secure(ui));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public TavernaServerListenersREST.Properties getProperties(UriInfo ui) {
+		return new TavernaServerListenersREST.Properties(secure(ui).path(
+				"{prop}"), listen.listProperties());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public TavernaServerListenersREST.Property getProperty(
+			final String propertyName) throws NoListenerException {
+		List<String> p = asList(listen.listProperties());
+		if (p.contains(propertyName)) {
+			return makePropertyInterface().connect(listen, run, propertyName);
+		}
+		throw new NoListenerException("no such property");
+	}
+
+	protected abstract ListenerPropertyREST makePropertyInterface();
+
+	@Override
+	@CallCounted
+	public Response listenerOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response configurationOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response propertiesOptions() {
+		return opt();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServer.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServer.java
new file mode 100644
index 0000000..4844147
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServer.java
@@ -0,0 +1,1438 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static java.lang.Math.min;
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.sort;
+import static java.util.UUID.randomUUID;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static javax.xml.ws.handler.MessageContext.HTTP_REQUEST_HEADERS;
+import static javax.xml.ws.handler.MessageContext.PATH_INFO;
+import static org.apache.commons.io.IOUtils.toByteArray;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.TavernaServerSupport.PROV_BUNDLE;
+import static org.taverna.server.master.common.DirEntryReference.newInstance;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Roles.ADMIN;
+import static org.taverna.server.master.common.Roles.SELF;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.common.Status.Initialized;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.soap.DirEntry.convert;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.PreDestroy;
+import javax.annotation.Resource;
+import javax.annotation.security.DeclareRoles;
+import javax.annotation.security.RolesAllowed;
+import javax.jws.WebService;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.JAXBException;
+import javax.xml.ws.WebServiceContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.cxf.annotations.WSDLDocumentation;
+import org.apache.taverna.server.usagerecord.JobUsageRecord;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.SupportAware;
+import org.taverna.server.master.api.TavernaServerBean;
+import org.taverna.server.master.common.Capability;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.DirEntryReference;
+import org.taverna.server.master.common.InputDescription;
+import org.taverna.server.master.common.Permission;
+import org.taverna.server.master.common.ProfileList;
+import org.taverna.server.master.common.RunReference;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.common.version.Version;
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoCredentialException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.exceptions.NotOwnerException;
+import org.taverna.server.master.exceptions.OverloadedException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.factories.ListenerFactory;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.Input;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.RunStore;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.notification.NotificationEngine;
+import org.taverna.server.master.notification.atom.EventDAO;
+import org.taverna.server.master.rest.TavernaServerREST;
+import org.taverna.server.master.rest.TavernaServerREST.EnabledNotificationFabrics;
+import org.taverna.server.master.rest.TavernaServerREST.PermittedListeners;
+import org.taverna.server.master.rest.TavernaServerREST.PermittedWorkflows;
+import org.taverna.server.master.rest.TavernaServerREST.PolicyView;
+import org.taverna.server.master.rest.TavernaServerRunREST;
+import org.taverna.server.master.soap.DirEntry;
+import org.taverna.server.master.soap.FileContents;
+import org.taverna.server.master.soap.PermissionList;
+import org.taverna.server.master.soap.TavernaServerSOAP;
+import org.taverna.server.master.soap.WrappedWorkflow;
+import org.taverna.server.master.soap.ZippedDirectory;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.taverna.server.port_description.OutputDescription;
+
+/**
+ * The core implementation of the web application.
+ * 
+ * @author Donal Fellows
+ */
+@Path("/")
+@DeclareRoles({ USER, ADMIN })
+@WebService(endpointInterface = "org.taverna.server.master.soap.TavernaServerSOAP", serviceName = "TavernaServer", targetNamespace = SERVER_SOAP)
+@WSDLDocumentation("An instance of Taverna " + Version.JAVA + " Server.")
+public abstract class TavernaServer implements TavernaServerSOAP,
+		TavernaServerREST, TavernaServerBean {
+	/**
+	 * The root of descriptions of the server in JMX.
+	 */
+	public static final String JMX_ROOT = "Taverna:group=Server-"
+			+ Version.JAVA + ",name=";
+
+	/** The logger for the server framework. */
+	public Log log = getLog("Taverna.Server.Webapp");
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+	// CONNECTIONS TO JMX, SPRING AND CXF
+
+	@Resource
+	WebServiceContext jaxws;
+	@Context
+	private HttpHeaders jaxrsHeaders;
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+	// STATE VARIABLES AND SPRING SETTERS
+
+	/**
+	 * For building descriptions of the expected inputs and actual outputs of a
+	 * workflow.
+	 */
+	private ContentsDescriptorBuilder cdBuilder;
+	/**
+	 * Utilities for accessing files on the local-worker.
+	 */
+	private FilenameUtils fileUtils;
+	/** How notifications are dispatched. */
+	private NotificationEngine notificationEngine;
+	/** Main support class. */
+	private TavernaServerSupport support;
+	/** A storage facility for workflow runs. */
+	private RunStore runStore;
+	/** Encapsulates the policies applied by this server. */
+	private Policy policy;
+	/** Where Atom events come from. */
+	EventDAO eventSource;
+	/** Reference to the main interaction feed. */
+	private String interactionFeed;
+
+	@Override
+	@Required
+	public void setFileUtils(FilenameUtils converter) {
+		this.fileUtils = converter;
+	}
+
+	@Override
+	@Required
+	public void setContentsDescriptorBuilder(ContentsDescriptorBuilder cdBuilder) {
+		this.cdBuilder = cdBuilder;
+	}
+
+	@Override
+	@Required
+	public void setNotificationEngine(NotificationEngine notificationEngine) {
+		this.notificationEngine = notificationEngine;
+	}
+
+	/**
+	 * @param support
+	 *            the support to set
+	 */
+	@Override
+	@Required
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	@Required
+	public void setRunStore(RunStore runStore) {
+		this.runStore = runStore;
+	}
+
+	@Override
+	@Required
+	public void setPolicy(Policy policy) {
+		this.policy = policy;
+	}
+
+	@Override
+	@Required
+	public void setEventSource(EventDAO eventSource) {
+		this.eventSource = eventSource;
+	}
+
+	/**
+	 * The location of a service-wide interaction feed, derived from a
+	 * properties file. Expected to be <i>actually</i> not set (to a real
+	 * value).
+	 * 
+	 * @param interactionFeed
+	 *            The URL, which will be resolved relative to the location of
+	 *            the webapp, or the string "<tt>none</tt>" (which corresponds
+	 *            to a <tt>null</tt>).
+	 */
+	public void setInteractionFeed(String interactionFeed) {
+		if ("none".equals(interactionFeed))
+			interactionFeed = null;
+		else if (interactionFeed != null && interactionFeed.startsWith("${"))
+			interactionFeed = null;
+		this.interactionFeed = interactionFeed;
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+	// REST INTERFACE
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public ServerDescription describeService(UriInfo ui) {
+		jaxrsUriInfo.set(new WeakReference<>(ui));
+		return new ServerDescription(ui, resolve(interactionFeed));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public RunList listUsersRuns(UriInfo ui) {
+		jaxrsUriInfo.set(new WeakReference<>(ui));
+		return new RunList(runs(), secure(ui).path("{name}"));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response submitWorkflow(Workflow workflow, UriInfo ui)
+			throws NoUpdateException {
+		jaxrsUriInfo.set(new WeakReference<>(ui));
+		checkCreatePolicy(workflow);
+		String name = support.buildWorkflow(workflow);
+		return created(secure(ui).path("{uuid}").build(name)).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response submitWorkflowByURL(List<URI> referenceList, UriInfo ui)
+			throws NoCreateException {
+		jaxrsUriInfo.set(new WeakReference<>(ui));
+		if (referenceList == null || referenceList.size() == 0)
+			throw new NoCreateException("no workflow URI supplied");
+		URI workflowURI = referenceList.get(0);
+		checkCreatePolicy(workflowURI);
+		Workflow workflow;
+		try {
+			workflow = support.getWorkflowDocumentFromURI(workflowURI);
+		} catch (IOException e) {
+			throw new NoCreateException("could not read workflow", e);
+		}
+		String name = support.buildWorkflow(workflow);
+		return created(secure(ui).path("{uuid}").build(name)).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public int getServerMaxRuns() {
+		return support.getMaxSimultaneousRuns();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public TavernaServerRunREST getRunResource(String runName, UriInfo ui)
+			throws UnknownRunException {
+		jaxrsUriInfo.set(new WeakReference<>(ui));
+		RunREST rr = makeRunInterface();
+		rr.setRun(support.getRun(runName));
+		rr.setRunName(runName);
+		return rr;
+	}
+
+	private ThreadLocal<Reference<UriInfo>> jaxrsUriInfo = new InheritableThreadLocal<>();
+
+	private UriInfo getUriInfo() {
+		if (jaxrsUriInfo.get() == null)
+			return null;
+		return jaxrsUriInfo.get().get();
+	}
+
+	@Override
+	@CallCounted
+	public abstract PolicyView getPolicyDescription();
+
+	@Override
+	@CallCounted
+	public Response serviceOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response runsOptions() {
+		return opt("POST");
+	}
+
+	/**
+	 * Construct a RESTful interface to a run.
+	 * 
+	 * @return The handle to the interface, as decorated by Spring.
+	 */
+	protected abstract RunREST makeRunInterface();
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+	// SOAP INTERFACE
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public RunReference[] listRuns() {
+		ArrayList<RunReference> ws = new ArrayList<>();
+		UriBuilder ub = getRunUriBuilder();
+		for (String runName : runs().keySet())
+			ws.add(new RunReference(runName, ub));
+		return ws.toArray(new RunReference[ws.size()]);
+	}
+
+	private void checkCreatePolicy(Workflow workflow) throws NoCreateException {
+		List<URI> pwu = policy
+				.listPermittedWorkflowURIs(support.getPrincipal());
+		if (pwu == null || pwu.size() == 0)
+			return;
+		throw new NoCreateException("server policy: will only start "
+				+ "workflows sourced from permitted URI list");
+	}
+
+	private void checkCreatePolicy(URI workflowURI) throws NoCreateException {
+		List<URI> pwu = policy
+				.listPermittedWorkflowURIs(support.getPrincipal());
+		if (pwu == null || pwu.size() == 0 || pwu.contains(workflowURI))
+			return;
+		throw new NoCreateException("workflow URI not on permitted list");
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public RunReference submitWorkflow(Workflow workflow)
+			throws NoUpdateException {
+		checkCreatePolicy(workflow);
+		String name = support.buildWorkflow(workflow);
+		return new RunReference(name, getRunUriBuilder());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public RunReference submitWorkflowMTOM(WrappedWorkflow workflow)
+			throws NoUpdateException {
+		Workflow wf;
+		try {
+			wf = workflow.getWorkflow();
+		} catch (IOException e) {
+			throw new NoCreateException(e.getMessage(), e);
+		}
+		checkCreatePolicy(wf);
+		String name = support.buildWorkflow(wf);
+		return new RunReference(name, getRunUriBuilder());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public RunReference submitWorkflowByURI(URI workflowURI)
+			throws NoCreateException {
+		checkCreatePolicy(workflowURI);
+		Workflow workflow;
+		try {
+			workflow = support.getWorkflowDocumentFromURI(workflowURI);
+		} catch (IOException e) {
+			throw new NoCreateException("could not read workflow", e);
+		}
+		String name = support.buildWorkflow(workflow);
+		return new RunReference(name, getRunUriBuilder());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public URI[] getServerWorkflows() {
+		return support.getPermittedWorkflowURIs();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String[] getServerListeners() {
+		List<String> types = support.getListenerTypes();
+		return types.toArray(new String[types.size()]);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String[] getServerNotifiers() {
+		List<String> dispatchers = notificationEngine
+				.listAvailableDispatchers();
+		return dispatchers.toArray(new String[dispatchers.size()]);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public List<Capability> getServerCapabilities() {
+		return support.getCapabilities();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void destroyRun(String runName) throws UnknownRunException,
+			NoUpdateException {
+		support.unregisterRun(runName, null);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getRunDescriptiveName(String runName)
+			throws UnknownRunException {
+		return support.getRun(runName).getName();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunDescriptiveName(String runName, String descriptiveName)
+			throws UnknownRunException, NoUpdateException {
+		TavernaRun run = support.getRun(runName);
+		support.permitUpdate(run);
+		run.setName(descriptiveName);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Workflow getRunWorkflow(String runName) throws UnknownRunException {
+		return support.getRun(runName).getWorkflow();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public WrappedWorkflow getRunWorkflowMTOM(String runName)
+			throws UnknownRunException {
+		WrappedWorkflow ww = new WrappedWorkflow();
+		ww.setWorkflow(support.getRun(runName).getWorkflow());
+		return ww;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public ProfileList getRunWorkflowProfiles(String runName)
+			throws UnknownRunException {
+		return support.getProfileDescriptor(support.getRun(runName)
+				.getWorkflow());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Date getRunExpiry(String runName) throws UnknownRunException {
+		return support.getRun(runName).getExpiry();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunExpiry(String runName, Date d)
+			throws UnknownRunException, NoUpdateException {
+		support.updateExpiry(support.getRun(runName), d);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Date getRunCreationTime(String runName) throws UnknownRunException {
+		return support.getRun(runName).getCreationTimestamp();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Date getRunFinishTime(String runName) throws UnknownRunException {
+		return support.getRun(runName).getFinishTimestamp();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Date getRunStartTime(String runName) throws UnknownRunException {
+		return support.getRun(runName).getStartTimestamp();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Status getRunStatus(String runName) throws UnknownRunException {
+		return support.getRun(runName).getStatus();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String setRunStatus(String runName, Status s)
+			throws UnknownRunException, NoUpdateException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		if (s == Status.Operating && w.getStatus() == Status.Initialized) {
+			if (!support.getAllowStartWorkflowRuns())
+				throw new OverloadedException();
+			try {
+				String issue = w.setStatus(s);
+				if (issue == null)
+					return "";
+				if (issue.isEmpty())
+					return "unknown reason for partial change";
+				return issue;
+			} catch (RuntimeException | NoUpdateException e) {
+				log.info("failed to start run " + runName, e);
+				throw e;
+			}
+		} else {
+			w.setStatus(s);
+			return "";
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getRunStdout(String runName) throws UnknownRunException {
+		try {
+			return support.getProperty(runName, "io", "stdout");
+		} catch (NoListenerException e) {
+			return "";
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getRunStderr(String runName) throws UnknownRunException {
+		try {
+			return support.getProperty(runName, "io", "stderr");
+		} catch (NoListenerException e) {
+			return "";
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public JobUsageRecord getRunUsageRecord(String runName)
+			throws UnknownRunException {
+		try {
+			String ur = support.getProperty(runName, "io", "usageRecord");
+			if (ur.isEmpty())
+				return null;
+			return JobUsageRecord.unmarshal(ur);
+		} catch (NoListenerException e) {
+			return null;
+		} catch (JAXBException e) {
+			log.info("failed to deserialize non-empty usage record", e);
+			return null;
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getRunLog(String runName) throws UnknownRunException {
+		try {
+			return support.getLogs(support.getRun(runName)).get("UTF-8");
+		} catch (UnsupportedEncodingException e) {
+			log.warn("unexpected encoding problem", e);
+			return "";
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public FileContents getRunBundle(String runName)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		File f = fileUtils.getFile(support.getRun(runName), PROV_BUNDLE);
+		FileContents fc = new FileContents();
+		// We *know* the content type, by definition
+		fc.setFile(f, "application/vnd.wf4ever.robundle+zip");
+		return fc;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public boolean getRunGenerateProvenance(String runName)
+			throws UnknownRunException {
+		return support.getRun(runName).getGenerateProvenance();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunGenerateProvenance(String runName, boolean generate)
+			throws UnknownRunException, NoUpdateException {
+		TavernaRun run = support.getRun(runName);
+		support.permitUpdate(run);
+		run.setGenerateProvenance(generate);
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+	// SOAP INTERFACE - Security
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getRunOwner(String runName) throws UnknownRunException {
+		return support.getRun(runName).getSecurityContext().getOwner()
+				.getName();
+	}
+
+	/**
+	 * Look up a security context, applying access control rules for access to
+	 * the parts of the context that are only open to the owner.
+	 * 
+	 * @param runName
+	 *            The name of the workflow run.
+	 * @param initialOnly
+	 *            Whether to check if we're in the initial state.
+	 * @return The security context. Never <tt>null</tt>.
+	 * @throws UnknownRunException
+	 * @throws NotOwnerException
+	 * @throws BadStateChangeException
+	 */
+	private TavernaSecurityContext getRunSecurityContext(String runName,
+			boolean initialOnly) throws UnknownRunException, NotOwnerException,
+			BadStateChangeException {
+		TavernaRun run = support.getRun(runName);
+		TavernaSecurityContext c = run.getSecurityContext();
+		if (!c.getOwner().equals(support.getPrincipal()))
+			throw new NotOwnerException();
+		if (initialOnly && run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		return c;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Credential[] getRunCredentials(String runName)
+			throws UnknownRunException, NotOwnerException {
+		try {
+			return getRunSecurityContext(runName, false).getCredentials();
+		} catch (BadStateChangeException e) {
+			Error e2 = new Error("impossible");
+			e2.initCause(e);
+			throw e2;
+		}
+	}
+
+	private Credential findCredential(TavernaSecurityContext c, String id)
+			throws NoCredentialException {
+		for (Credential t : c.getCredentials())
+			if (t.id.equals(id))
+				return t;
+		throw new NoCredentialException();
+	}
+
+	private Trust findTrust(TavernaSecurityContext c, String id)
+			throws NoCredentialException {
+		for (Trust t : c.getTrusted())
+			if (t.id.equals(id))
+				return t;
+		throw new NoCredentialException();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String setRunCredential(String runName, String credentialID,
+			Credential credential) throws UnknownRunException,
+			NotOwnerException, InvalidCredentialException,
+			NoCredentialException, BadStateChangeException {
+		TavernaSecurityContext c = getRunSecurityContext(runName, true);
+		if (credentialID == null || credentialID.isEmpty()) {
+			credential.id = randomUUID().toString();
+		} else {
+			credential.id = findCredential(c, credentialID).id;
+		}
+		URI uri = getRunUriBuilder().path("security/credentials/{credid}")
+				.build(runName, credential.id);
+		credential.href = uri.toString();
+		c.validateCredential(credential);
+		c.addCredential(credential);
+		return credential.id;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void deleteRunCredential(String runName, String credentialID)
+			throws UnknownRunException, NotOwnerException,
+			NoCredentialException, BadStateChangeException {
+		getRunSecurityContext(runName, true).deleteCredential(
+				new Credential.Dummy(credentialID));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Trust[] getRunCertificates(String runName)
+			throws UnknownRunException, NotOwnerException {
+		try {
+			return getRunSecurityContext(runName, false).getTrusted();
+		} catch (BadStateChangeException e) {
+			Error e2 = new Error("impossible");
+			e2.initCause(e);
+			throw e2;
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String setRunCertificates(String runName, String certificateID,
+			Trust certificate) throws UnknownRunException, NotOwnerException,
+			InvalidCredentialException, NoCredentialException,
+			BadStateChangeException {
+		TavernaSecurityContext c = getRunSecurityContext(runName, true);
+		if (certificateID == null || certificateID.isEmpty()) {
+			certificate.id = randomUUID().toString();
+		} else {
+			certificate.id = findTrust(c, certificateID).id;
+		}
+		URI uri = getRunUriBuilder().path("security/trusts/{certid}").build(
+				runName, certificate.id);
+		certificate.href = uri.toString();
+		c.validateTrusted(certificate);
+		c.addTrusted(certificate);
+		return certificate.id;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void deleteRunCertificates(String runName, String certificateID)
+			throws UnknownRunException, NotOwnerException,
+			NoCredentialException, BadStateChangeException {
+		TavernaSecurityContext c = getRunSecurityContext(runName, true);
+		Trust toDelete = new Trust();
+		toDelete.id = certificateID;
+		c.deleteTrusted(toDelete);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public PermissionList listRunPermissions(String runName)
+			throws UnknownRunException, NotOwnerException {
+		PermissionList pl = new PermissionList();
+		pl.permission = new ArrayList<>();
+		Map<String, Permission> perm;
+		try {
+			perm = support.getPermissionMap(getRunSecurityContext(runName,
+					false));
+		} catch (BadStateChangeException e) {
+			log.error("unexpected error from internal API", e);
+			perm = emptyMap();
+		}
+		List<String> users = new ArrayList<>(perm.keySet());
+		sort(users);
+		for (String user : users)
+			pl.permission.add(new PermissionList.SinglePermissionMapping(user,
+					perm.get(user)));
+		return pl;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunPermission(String runName, String userName,
+			Permission permission) throws UnknownRunException,
+			NotOwnerException {
+		try {
+			support.setPermission(getRunSecurityContext(runName, false),
+					userName, permission);
+		} catch (BadStateChangeException e) {
+			log.error("unexpected error from internal API", e);
+		}
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+	// SOAP INTERFACE - Filesystem connection
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public OutputDescription getRunOutputDescription(String runName)
+			throws UnknownRunException, BadStateChangeException,
+			FilesystemAccessException, NoDirectoryEntryException {
+		TavernaRun run = support.getRun(runName);
+		if (run.getStatus() == Initialized)
+			throw new BadStateChangeException(
+					"may not get output description in initial state");
+		return cdBuilder.makeOutputDescriptor(run, null);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public DirEntry[] getRunDirectoryContents(String runName, DirEntry d)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		List<DirEntry> result = new ArrayList<>();
+		for (DirectoryEntry e : fileUtils.getDirectory(support.getRun(runName),
+				convert(d)).getContents())
+			result.add(convert(newInstance(null, e)));
+		return result.toArray(new DirEntry[result.size()]);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public byte[] getRunDirectoryAsZip(String runName, DirEntry d)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		try {
+			return toByteArray(fileUtils.getDirectory(support.getRun(runName),
+					convert(d)).getContentsAsZip());
+		} catch (IOException e) {
+			throw new FilesystemAccessException("problem serializing ZIP data",
+					e);
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public ZippedDirectory getRunDirectoryAsZipMTOM(String runName, DirEntry d)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		return new ZippedDirectory(fileUtils.getDirectory(
+				support.getRun(runName), convert(d)));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public DirEntry makeRunDirectory(String runName, DirEntry parent,
+			String name) throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		Directory dir = fileUtils.getDirectory(w, convert(parent))
+				.makeSubdirectory(support.getPrincipal(), name);
+		return convert(newInstance(null, dir));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public DirEntry makeRunFile(String runName, DirEntry parent, String name)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		File f = fileUtils.getDirectory(w, convert(parent)).makeEmptyFile(
+				support.getPrincipal(), name);
+		return convert(newInstance(null, f));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void destroyRunDirectoryEntry(String runName, DirEntry d)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		fileUtils.getDirEntry(w, convert(d)).destroy();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public byte[] getRunFileContents(String runName, DirEntry d)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		File f = fileUtils.getFile(support.getRun(runName), convert(d));
+		return f.getContents(0, -1);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunFileContents(String runName, DirEntry d,
+			byte[] newContents) throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		fileUtils.getFile(w, convert(d)).setContents(newContents);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public FileContents getRunFileContentsMTOM(String runName, DirEntry d)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		File f = fileUtils.getFile(support.getRun(runName), convert(d));
+		FileContents fc = new FileContents();
+		fc.setFile(f, support.getEstimatedContentType(f));
+		return fc;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunFileContentsFromURI(String runName,
+			DirEntryReference file, URI reference)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException {
+		TavernaRun run = support.getRun(runName);
+		support.permitUpdate(run);
+		File f = fileUtils.getFile(run, file);
+		try {
+			support.copyDataToFile(reference, f);
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"problem transferring data from URI", e);
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunFileContentsMTOM(String runName, FileContents newContents)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException {
+		TavernaRun run = support.getRun(runName);
+		support.permitUpdate(run);
+		File f = fileUtils.getFile(run, newContents.name);
+		f.setContents(new byte[0]);
+		support.copyDataToFile(newContents.fileData, f);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getRunFileType(String runName, DirEntry d)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		return support.getEstimatedContentType(fileUtils.getFile(
+				support.getRun(runName), convert(d)));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public long getRunFileLength(String runName, DirEntry d)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		return fileUtils.getFile(support.getRun(runName), convert(d)).getSize();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Date getRunFileModified(String runName, DirEntry d)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		return fileUtils.getFile(support.getRun(runName), convert(d))
+				.getModificationDate();
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+	// SOAP INTERFACE - Run listeners
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String[] getRunListeners(String runName) throws UnknownRunException {
+		TavernaRun w = support.getRun(runName);
+		List<String> result = new ArrayList<>();
+		for (Listener l : w.getListeners())
+			result.add(l.getName());
+		return result.toArray(new String[result.size()]);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String addRunListener(String runName, String listenerType,
+			String configuration) throws UnknownRunException,
+			NoUpdateException, NoListenerException {
+		return support.makeListener(support.getRun(runName), listenerType,
+				configuration).getName();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getRunListenerConfiguration(String runName,
+			String listenerName) throws UnknownRunException,
+			NoListenerException {
+		return support.getListener(runName, listenerName).getConfiguration();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String[] getRunListenerProperties(String runName, String listenerName)
+			throws UnknownRunException, NoListenerException {
+		return support.getListener(runName, listenerName).listProperties()
+				.clone();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getRunListenerProperty(String runName, String listenerName,
+			String propName) throws UnknownRunException, NoListenerException {
+		return support.getListener(runName, listenerName).getProperty(propName);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunListenerProperty(String runName, String listenerName,
+			String propName, String value) throws UnknownRunException,
+			NoUpdateException, NoListenerException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		Listener l = support.getListener(w, listenerName);
+		try {
+			l.getProperty(propName); // sanity check!
+			l.setProperty(propName, value);
+		} catch (RuntimeException e) {
+			throw new NoListenerException("problem setting property: "
+					+ e.getMessage(), e);
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public InputDescription getRunInputs(String runName)
+			throws UnknownRunException {
+		return new InputDescription(support.getRun(runName));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getRunOutputBaclavaFile(String runName)
+			throws UnknownRunException {
+		return support.getRun(runName).getOutputBaclavaFile();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunInputBaclavaFile(String runName, String fileName)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, BadStateChangeException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		w.setInputBaclavaFile(fileName);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunInputPortFile(String runName, String portName,
+			String portFilename) throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, BadStateChangeException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		Input i = support.getInput(w, portName);
+		if (i == null)
+			i = w.makeInput(portName);
+		i.setFile(portFilename);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunInputPortValue(String runName, String portName,
+			String portValue) throws UnknownRunException, NoUpdateException,
+			BadStateChangeException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		Input i = support.getInput(w, portName);
+		if (i == null)
+			i = w.makeInput(portName);
+		i.setValue(portValue);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunInputPortListDelimiter(String runName, String portName,
+			String delimiter) throws UnknownRunException, NoUpdateException,
+			BadStateChangeException, BadPropertyValueException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		Input i = support.getInput(w, portName);
+		if (i == null)
+			i = w.makeInput(portName);
+		if (delimiter != null && delimiter.isEmpty())
+			delimiter = null;
+		if (delimiter != null) {
+			if (delimiter.length() > 1)
+				throw new BadPropertyValueException("delimiter too long");
+			if (delimiter.charAt(0) < 1 || delimiter.charAt(0) > 127)
+				throw new BadPropertyValueException(
+						"delimiter character must be non-NUL ASCII");
+		}
+		i.setDelimiter(delimiter);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public void setRunOutputBaclavaFile(String runName, String outputFile)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, BadStateChangeException {
+		TavernaRun w = support.getRun(runName);
+		support.permitUpdate(w);
+		w.setOutputBaclavaFile(outputFile);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public org.taverna.server.port_description.InputDescription getRunInputDescriptor(
+			String runName) throws UnknownRunException {
+		return cdBuilder.makeInputDescriptor(support.getRun(runName), null);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getServerStatus() {
+		return support.getAllowNewWorkflowRuns() ? "operational" : "suspended";
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+	// SUPPORT METHODS
+
+	@Override
+	public boolean initObsoleteSOAPSecurity(TavernaSecurityContext c) {
+		try {
+			javax.xml.ws.handler.MessageContext msgCtxt = (jaxws == null ? null
+					: jaxws.getMessageContext());
+			if (msgCtxt == null)
+				return true;
+			c.initializeSecurityFromSOAPContext(msgCtxt);
+			return false;
+		} catch (IllegalStateException e) {
+			/* ignore; not much we can do */
+			return true;
+		}
+	}
+
+	@Override
+	public boolean initObsoleteRESTSecurity(TavernaSecurityContext c) {
+		if (jaxrsHeaders == null)
+			return true;
+		c.initializeSecurityFromRESTContext(jaxrsHeaders);
+		return false;
+	}
+
+	/**
+	 * A creator of substitute {@link URI} builders.
+	 * 
+	 * @return A URI builder configured so that it takes a path parameter that
+	 *         corresponds to the run ID (but with no such ID applied).
+	 */
+	UriBuilder getRunUriBuilder() {
+		return getBaseUriBuilder().path("runs/{uuid}");
+	}
+
+	@Override
+	public UriBuilder getRunUriBuilder(TavernaRun run) {
+		return fromUri(getRunUriBuilder().build(run.getId()));
+	}
+
+	private final String DEFAULT_HOST = "localhost:8080"; // Crappy default
+
+	private String getHostLocation() {
+		@java.lang.SuppressWarnings("unchecked")
+		Map<String, List<String>> headers = (Map<String, List<String>>) jaxws
+				.getMessageContext().get(HTTP_REQUEST_HEADERS);
+		if (headers != null) {
+			List<String> host = headers.get("HOST");
+			if (host != null && !host.isEmpty())
+				return host.get(0);
+		}
+		return DEFAULT_HOST;
+	}
+
+	@Nonnull
+	private URI getPossiblyInsecureBaseUri() {
+		// See if JAX-RS can supply the info
+		UriInfo ui = getUriInfo();
+		if (ui != null && ui.getBaseUri() != null)
+			return ui.getBaseUri();
+		// See if JAX-WS *cannot* supply the info
+		if (jaxws == null || jaxws.getMessageContext() == null)
+			// Hack to make the test suite work
+			return URI.create("http://" + DEFAULT_HOST
+					+ "/taverna-server/rest/");
+		String pathInfo = (String) jaxws.getMessageContext().get(PATH_INFO);
+		pathInfo = pathInfo.replaceFirst("/soap$", "/rest/");
+		pathInfo = pathInfo.replaceFirst("/rest/.+$", "/rest/");
+		return URI.create("http://" + getHostLocation() + pathInfo);
+	}
+
+	@Override
+	public UriBuilder getBaseUriBuilder() {
+		return secure(fromUri(getPossiblyInsecureBaseUri()));
+	}
+
+	@Override
+	@Nullable
+	public String resolve(@Nullable String uri) {
+		if (uri == null)
+			return null;
+		return secure(getPossiblyInsecureBaseUri(), uri).toString();
+	}
+
+	private Map<String, TavernaRun> runs() {
+		return runStore.listRuns(support.getPrincipal(), policy);
+	}
+}
+
+/**
+ * RESTful interface to the policies of a Taverna Server installation.
+ * 
+ * @author Donal Fellows
+ */
+class PolicyREST implements PolicyView, SupportAware {
+	private TavernaServerSupport support;
+	private Policy policy;
+	private ListenerFactory listenerFactory;
+	private NotificationEngine notificationEngine;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Required
+	public void setPolicy(Policy policy) {
+		this.policy = policy;
+	}
+
+	@Required
+	public void setListenerFactory(ListenerFactory listenerFactory) {
+		this.listenerFactory = listenerFactory;
+	}
+
+	@Required
+	public void setNotificationEngine(NotificationEngine notificationEngine) {
+		this.notificationEngine = notificationEngine;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public PolicyDescription getDescription(UriInfo ui) {
+		return new PolicyDescription(ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public int getMaxSimultaneousRuns() {
+		Integer limit = policy.getMaxRuns(support.getPrincipal());
+		if (limit == null)
+			return policy.getMaxRuns();
+		return min(limit.intValue(), policy.getMaxRuns());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public PermittedListeners getPermittedListeners() {
+		return new PermittedListeners(
+				listenerFactory.getSupportedListenerTypes());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public PermittedWorkflows getPermittedWorkflows() {
+		return new PermittedWorkflows(policy.listPermittedWorkflowURIs(support
+				.getPrincipal()));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public EnabledNotificationFabrics getEnabledNotifiers() {
+		return new EnabledNotificationFabrics(
+				notificationEngine.listAvailableDispatchers());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public int getMaxOperatingRuns() {
+		return policy.getOperatingLimit();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public CapabilityList getCapabilities() {
+		CapabilityList cl = new CapabilityList();
+		cl.capability.addAll(support.getCapabilities());
+		return cl;
+	}
+}


[14/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java
deleted file mode 100644
index c733d89..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- */
-package org.taverna.server.master.identity;
-/*
- * 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.
- */
-
-import static java.util.Collections.synchronizedMap;
-import static org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes;
-import static org.taverna.server.master.common.Roles.SELF;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.security.authentication.AuthenticationServiceException;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.web.authentication.WebAuthenticationDetails;
-import org.springframework.web.context.request.ServletRequestAttributes;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.worker.RunDatabaseDAO;
-
-/**
- * A special authentication provider that allows a workflow to authenticate to
- * itself. This is used to allow the workflow to publish to its own interaction
- * feed.
- * 
- * @author Donal Fellows
- */
-public class WorkflowInternalAuthProvider extends
-		AbstractUserDetailsAuthenticationProvider {
-	private Log log = LogFactory.getLog("Taverna.Server.UserDB");
-	private static final boolean logDecisions = true;
-	public static final String PREFIX = "wfrun_";
-	private RunDatabaseDAO dao;
-	private Map<String, String> cache;
-
-	@Required
-	public void setDao(RunDatabaseDAO dao) {
-		this.dao = dao;
-	}
-
-	@Required
-	@SuppressWarnings("serial")
-	public void setCacheBound(final int bound) {
-		cache = synchronizedMap(new LinkedHashMap<String, String>() {
-			@Override
-			protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
-				return size() > bound;
-			}
-		});
-	}
-
-	public void setAuthorizedAddresses(String[] addresses) {
-		authorizedAddresses = new HashSet<>(localAddresses);
-		for (String s : addresses)
-			authorizedAddresses.add(s);
-	}
-
-	@PostConstruct
-	public void logConfig() {
-		log.info("authorized addresses for automatic access: "
-				+ authorizedAddresses);
-	}
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	private final Set<String> localAddresses = new HashSet<>();
-	private Set<String> authorizedAddresses;
-	{
-		localAddresses.add("127.0.0.1"); // IPv4
-		localAddresses.add("::1"); // IPv6
-		try {
-			InetAddress addr = InetAddress.getLocalHost();
-			if (!addr.isLoopbackAddress())
-				localAddresses.add(addr.getHostAddress());
-		} catch (UnknownHostException e) {
-			// Ignore the exception
-		}
-		authorizedAddresses = new HashSet<>(localAddresses);
-	}
-
-	/**
-	 * Check that the authentication request is actually valid for the given
-	 * user record.
-	 * 
-	 * @param userRecord
-	 *            as retrieved from the
-	 *            {@link #retrieveUser(String, UsernamePasswordAuthenticationToken)}
-	 *            or <code>UserCache</code>
-	 * @param principal
-	 *            the principal that is trying to authenticate (and that we're
-	 *            trying to bind)
-	 * @param credentials
-	 *            the credentials (e.g., password) presented by the principal
-	 * 
-	 * @throws AuthenticationException
-	 *             AuthenticationException if the credentials could not be
-	 *             validated (generally a <code>BadCredentialsException</code>,
-	 *             an <code>AuthenticationServiceException</code>)
-	 * @throws Exception
-	 *             If something goes wrong. Will be logged and converted to a
-	 *             generic AuthenticationException.
-	 */
-	protected void additionalAuthenticationChecks(UserDetails userRecord,
-			@Nonnull Object principal, @Nonnull Object credentials)
-			throws Exception {
-		@Nonnull
-		HttpServletRequest req = ((ServletRequestAttributes) currentRequestAttributes())
-				.getRequest();
-
-		// Are we coming from a "local" address?
-		if (!req.getLocalAddr().equals(req.getRemoteAddr())
-				&& !authorizedAddresses.contains(req.getRemoteAddr())) {
-			if (logDecisions)
-				log.info("attempt to use workflow magic token from untrusted address:"
-						+ " token="
-						+ userRecord.getUsername()
-						+ ", address="
-						+ req.getRemoteAddr());
-			throw new BadCredentialsException("bad login token");
-		}
-
-		// Does the password match?
-		if (!credentials.equals(userRecord.getPassword())) {
-			if (logDecisions)
-				log.info("workflow magic token is untrusted due to password mismatch:"
-						+ " wanted="
-						+ userRecord.getPassword()
-						+ ", got="
-						+ credentials);
-			throw new BadCredentialsException("bad login token");
-		}
-
-		if (logDecisions)
-			log.info("granted role " + SELF + " to user "
-					+ userRecord.getUsername());
-	}
-
-	/**
-	 * Retrieve the <code>UserDetails</code> from the relevant store, with the
-	 * option of throwing an <code>AuthenticationException</code> immediately if
-	 * the presented credentials are incorrect (this is especially useful if it
-	 * is necessary to bind to a resource as the user in order to obtain or
-	 * generate a <code>UserDetails</code>).
-	 * 
-	 * @param username
-	 *            The username to retrieve
-	 * @param details
-	 *            The details from the authentication request.
-	 * @see #retrieveUser(String,UsernamePasswordAuthenticationToken)
-	 * @return the user information (never <code>null</code> - instead an
-	 *         exception should the thrown)
-	 * @throws AuthenticationException
-	 *             if the credentials could not be validated (generally a
-	 *             <code>BadCredentialsException</code>, an
-	 *             <code>AuthenticationServiceException</code> or
-	 *             <code>UsernameNotFoundException</code>)
-	 * @throws Exception
-	 *             If something goes wrong. It will be logged and converted into
-	 *             a general AuthenticationException.
-	 */
-	@Nonnull
-	protected UserDetails retrieveUser(String username, Object details)
-			throws Exception {
-		if (details == null || !(details instanceof WebAuthenticationDetails))
-			throw new UsernameNotFoundException("context unsupported");
-		if (!username.startsWith(PREFIX))
-			throw new UsernameNotFoundException(
-					"unsupported username for this provider");
-		if (logDecisions)
-			log.info("request for auth for user " + username);
-		String wfid = username.substring(PREFIX.length());
-		String securityToken;
-		try {
-			securityToken = cache.get(wfid);
-			if (securityToken == null) {
-				securityToken = dao.getSecurityToken(wfid);
-				if (securityToken == null)
-					throw new UsernameNotFoundException("no such user");
-				cache.put(wfid, securityToken);
-			}
-		} catch (NullPointerException npe) {
-			throw new UsernameNotFoundException("no such user");
-		}
-		return new User(username, securityToken, true, true, true, true,
-				Arrays.asList(new LiteralGrantedAuthority(SELF),
-						new WorkflowSelfAuthority(wfid)));
-	}
-
-	@Override
-	@PerfLogged
-	protected final void additionalAuthenticationChecks(UserDetails userRecord,
-			UsernamePasswordAuthenticationToken token) {
-		try {
-			additionalAuthenticationChecks(userRecord, token.getPrincipal(),
-					token.getCredentials());
-		} catch (AuthenticationException e) {
-			throw e;
-		} catch (Exception e) {
-			log.warn("unexpected failure in authentication", e);
-			throw new AuthenticationServiceException(
-					"unexpected failure in authentication", e);
-		}
-	}
-
-	@Override
-	@Nonnull
-	@PerfLogged
-	protected final UserDetails retrieveUser(String username,
-			UsernamePasswordAuthenticationToken token) {
-		try {
-			return retrieveUser(username, token.getDetails());
-		} catch (AuthenticationException e) {
-			throw e;
-		} catch (Exception e) {
-			log.warn("unexpected failure in authentication", e);
-			throw new AuthenticationServiceException(
-					"unexpected failure in authentication", e);
-		}
-	}
-
-	@SuppressWarnings("serial")
-	public static class WorkflowSelfAuthority extends LiteralGrantedAuthority {
-		public WorkflowSelfAuthority(String wfid) {
-			super(wfid);
-		}
-
-		public String getWorkflowID() {
-			return getAuthority();
-		}
-
-		@Override
-		public String toString() {
-			return "WORKFLOW(" + getAuthority() + ")";
-		}
-	}
-
-	public static class WorkflowSelfIDMapper implements LocalIdentityMapper {
-		private Log log = LogFactory.getLog("Taverna.Server.UserDB");
-		private RunStore runStore;
-
-		@PreDestroy
-		void closeLog() {
-			log = null;
-		}
-
-		@Required
-		public void setRunStore(RunStore runStore) {
-			this.runStore = runStore;
-		}
-
-		private String getUsernameForSelfAccess(WorkflowSelfAuthority authority)
-				throws UnknownRunException {
-			return runStore.getRun(authority.getWorkflowID())
-					.getSecurityContext().getOwner().getName();
-		}
-
-		@Override
-		@PerfLogged
-		public String getUsernameForPrincipal(UsernamePrincipal user) {
-			Authentication auth = SecurityContextHolder.getContext()
-					.getAuthentication();
-			if (auth == null || !auth.isAuthenticated())
-				return null;
-			try {
-				for (GrantedAuthority authority : auth.getAuthorities())
-					if (authority instanceof WorkflowSelfAuthority)
-						return getUsernameForSelfAccess((WorkflowSelfAuthority) authority);
-			} catch (UnknownRunException e) {
-				log.warn("workflow run disappeared during computation of workflow map identity");
-			}
-			return null;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java
deleted file mode 100644
index 14ad7db..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-/**
- * Implementations of beans that map global user identities to local
- * usernames.
- */
-package org.taverna.server.master.identity;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java
deleted file mode 100644
index 4b297dc..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- */
-package org.taverna.server.master.interaction;
-/*
- * 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.
- */
-
-import static java.lang.management.ManagementFactory.getPlatformMBeanServer;
-import static java.util.Collections.reverse;
-import static javax.management.Query.attr;
-import static javax.management.Query.match;
-import static javax.management.Query.value;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.annotation.Nullable;
-import javax.annotation.PostConstruct;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.factory.Factory;
-import org.apache.abdera.i18n.iri.IRI;
-import org.apache.abdera.model.Document;
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.model.Feed;
-import org.apache.abdera.parser.Parser;
-import org.apache.abdera.writer.Writer;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.TavernaServerSupport;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.FilenameUtils;
-
-/**
- * Bean that supports interaction feeds. This glues together the Abdera
- * serialization engine and the directory-based model used inside the server.
- * 
- * @author Donal Fellows
- */
-public class InteractionFeedSupport {
-	/**
-	 * The name of the resource within the run resource that is the run's
-	 * interaction feed resource.
-	 */
-	public static final String FEED_URL_DIR = "interaction";
-	/**
-	 * The name of the directory below the run working directory that will
-	 * contain the entries of the interaction feed.
-	 */
-	public static final String FEED_DIR = "feed";
-	/**
-	 * Should the contents of the entry be stripped when describing the overall
-	 * feed? This makes sense if (and only if) large entries are being pushed
-	 * through the feed.
-	 */
-	private static final boolean STRIP_CONTENTS = false;
-	/** Maximum size of an entry before truncation. */
-	private static final long MAX_ENTRY_SIZE = 50 * 1024;
-	/** Extension for entry files. */
-	private static final String EXT = ".atom";
-
-	private TavernaServerSupport support;
-	private FilenameUtils utils;
-	private Writer writer;
-	private Parser parser;
-	private Factory factory;
-	private UriBuilderFactory uriBuilder;
-
-	private AtomicInteger counter = new AtomicInteger();
-
-	@Required
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Required
-	public void setUtils(FilenameUtils utils) {
-		this.utils = utils;
-	}
-
-	@Required
-	public void setAbdera(Abdera abdera) {
-		this.factory = abdera.getFactory();
-		this.parser = abdera.getParser();
-		this.writer = abdera.getWriterFactory().getWriter("prettyxml");
-	}
-
-	@Required
-	// webapp
-	public void setUriBuilder(UriBuilderFactory uriBuilder) {
-		this.uriBuilder = uriBuilder;
-	}
-
-	private final Map<String, URL> endPoints = new HashMap<>();
-
-	@PostConstruct
-	void determinePorts() {
-		try {
-			MBeanServer mbs = getPlatformMBeanServer();
-			for (ObjectName obj : mbs.queryNames(new ObjectName(
-					"*:type=Connector,*"),
-					match(attr("protocol"), value("HTTP/1.1")))) {
-				String scheme = mbs.getAttribute(obj, "scheme").toString();
-				String port = obj.getKeyProperty("port");
-				endPoints.put(scheme, new URL(scheme + "://localhost:" + port));
-			}
-			getLog(getClass()).info(
-					"installed feed port publication mapping for "
-							+ endPoints.keySet());
-		} catch (Exception e) {
-			getLog(getClass()).error(
-					"failure in determining local port mapping", e);
-		}
-	}
-	
-	/**
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @return The URI of the feed
-	 */
-	public URI getFeedURI(TavernaRun run) {
-		return uriBuilder.getRunUriBuilder(run).path(FEED_URL_DIR).build();
-	}
-
-	@Nullable
-	public URL getLocalFeedBase(URI feedURI) {
-		if (feedURI == null)
-			return null;
-		return endPoints.get(feedURI.getScheme());
-	}
-
-	/**
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @param id
-	 *            The ID of the entry.
-	 * @return The URI of the entry.
-	 */
-	public URI getEntryURI(TavernaRun run, String id) {
-		return uriBuilder.getRunUriBuilder(run)
-				.path(FEED_URL_DIR + "/{entryID}").build(id);
-	}
-
-	private Entry getEntryFromFile(File f) throws FilesystemAccessException {
-		long size = f.getSize();
-		if (size > MAX_ENTRY_SIZE)
-			throw new FilesystemAccessException("entry larger than 50kB");
-		byte[] contents = f.getContents(0, (int) size);
-		Document<Entry> doc = parser.parse(new ByteArrayInputStream(contents));
-		return doc.getRoot();
-	}
-
-	private void putEntryInFile(Directory dir, String name, Entry contents)
-			throws FilesystemAccessException, NoUpdateException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		try {
-			writer.writeTo(contents, baos);
-		} catch (IOException e) {
-			throw new NoUpdateException("failed to serialize the ATOM entry", e);
-		}
-		File f = dir.makeEmptyFile(support.getPrincipal(), name);
-		f.appendContents(baos.toByteArray());
-	}
-
-	private List<DirectoryEntry> listPossibleEntries(TavernaRun run)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		List<DirectoryEntry> entries = new ArrayList<>(utils.getDirectory(run,
-				FEED_DIR).getContentsByDate());
-		reverse(entries);
-		return entries;
-	}
-
-	private String getRunURL(TavernaRun run) {
-		return new IRI(uriBuilder.getRunUriBuilder(run).build()).toString();
-	}
-
-	/**
-	 * Get the interaction feed for a partciular run.
-	 * 
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @return The Abdera feed descriptor.
-	 * @throws FilesystemAccessException
-	 *             If the feed directory can't be read for some reason.
-	 * @throws NoDirectoryEntryException
-	 *             If the feed directory doesn't exist or an entry is
-	 *             unexpectedly removed.
-	 */
-	public Feed getRunFeed(TavernaRun run) throws FilesystemAccessException,
-			NoDirectoryEntryException {
-		URI feedURI = getFeedURI(run);
-		Feed feed = factory.newFeed();
-		feed.setTitle("Interactions for Taverna Run \"" + run.getName() + "\"");
-		feed.addLink(new IRI(feedURI).toString(), "self");
-		feed.addLink(getRunURL(run), "workflowrun");
-		boolean fetchedDate = false;
-		for (DirectoryEntry de : listPossibleEntries(run)) {
-			if (!(de instanceof File))
-				continue;
-			try {
-				Entry e = getEntryFromFile((File) de);
-				if (STRIP_CONTENTS)
-					e.setContentElement(null);
-				feed.addEntry(e);
-				if (fetchedDate)
-					continue;
-				Date last = e.getUpdated();
-				if (last == null)
-					last = e.getPublished();
-				if (last == null)
-					last = de.getModificationDate();
-				feed.setUpdated(last);
-				fetchedDate = true;
-			} catch (FilesystemAccessException e) {
-				// Can't do anything about it, so we'll just drop the entry.
-			}
-		}
-		return feed;
-	}
-
-	/**
-	 * Gets the contents of a particular feed entry.
-	 * 
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @param entryID
-	 *            The identifier (from the path) of the entry to read.
-	 * @return The description of the entry.
-	 * @throws FilesystemAccessException
-	 *             If the entry can't be read or is too large.
-	 * @throws NoDirectoryEntryException
-	 *             If the entry can't be found.
-	 */
-	public Entry getRunFeedEntry(TavernaRun run, String entryID)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		File entryFile = utils.getFile(run, FEED_DIR + "/" + entryID + EXT);
-		return getEntryFromFile(entryFile);
-	}
-
-	/**
-	 * Given a partial feed entry, store a complete feed entry in the filesystem
-	 * for a particular run. Note that this does not permit update of an
-	 * existing entry; the entry is always created new.
-	 * 
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @param entry
-	 *            The partial entry to store
-	 * @return A link to the entry.
-	 * @throws FilesystemAccessException
-	 *             If the entry can't be stored.
-	 * @throws NoDirectoryEntryException
-	 *             If the run is improperly configured.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to do the write.
-	 * @throws MalformedURLException
-	 *             If a generated URL is illegal (shouldn't happen).
-	 */
-	public Entry addRunFeedEntry(TavernaRun run, Entry entry)
-			throws FilesystemAccessException, NoDirectoryEntryException,
-			NoUpdateException {
-		support.permitUpdate(run);
-		Date now = new Date();
-		entry.newId();
-		String localId = "entry_" + counter.incrementAndGet();
-		IRI selfLink = new IRI(getEntryURI(run, localId));
-		entry.addLink(selfLink.toString(), "self");
-		entry.addLink(getRunURL(run), "workflowrun");
-		entry.setUpdated(now);
-		entry.setPublished(now);
-		putEntryInFile(utils.getDirectory(run, FEED_DIR), localId + EXT, entry);
-		return getEntryFromFile(utils.getFile(run, FEED_DIR + "/" + localId
-				+ EXT));
-	}
-
-	/**
-	 * Deletes an entry from a feed.
-	 * 
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @param entryID
-	 *            The ID of the entry to delete.
-	 * @throws FilesystemAccessException
-	 *             If the entry can't be deleted
-	 * @throws NoDirectoryEntryException
-	 *             If the entry can't be found.
-	 * @throws NoUpdateException
-	 *             If the current user is not permitted to modify the run's
-	 *             characteristics.
-	 */
-	public void removeRunFeedEntry(TavernaRun run, String entryID)
-			throws FilesystemAccessException, NoDirectoryEntryException,
-			NoUpdateException {
-		support.permitUpdate(run);
-		utils.getFile(run, FEED_DIR + "/" + entryID + EXT).destroy();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java
deleted file mode 100644
index 54ec630..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-/**
- * This package contains the Atom feed implementation for interactions for a particular workflow run.
- * @author Donal Fellows
- */
-package org.taverna.server.master.interaction;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java
deleted file mode 100644
index bb74f5a..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import java.io.PipedInputStream;
-import java.security.Principal;
-import java.util.Collection;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-/**
- * Represents a directory that is the working directory of a workflow run, or a
- * sub-directory of it.
- * 
- * @author Donal Fellows
- * @see File
- */
-public interface Directory extends DirectoryEntry {
-	/**
-	 * @return A list of the contents of the directory.
-	 * @throws FilesystemAccessException
-	 *             If things go wrong.
-	 */
-	Collection<DirectoryEntry> getContents() throws FilesystemAccessException;
-
-	/**
-	 * @return A list of the contents of the directory, in guaranteed date
-	 *         order.
-	 * @throws FilesystemAccessException
-	 *             If things go wrong.
-	 */
-	Collection<DirectoryEntry> getContentsByDate()
-			throws FilesystemAccessException;
-
-	/**
-	 * @return The contents of the directory (and its sub-directories) as a zip.
-	 * @throws FilesystemAccessException
-	 *             If things go wrong.
-	 */
-	ZipStream getContentsAsZip() throws FilesystemAccessException;
-
-	/**
-	 * Creates a sub-directory of this directory.
-	 * 
-	 * @param actor
-	 *            Who this is being created by.
-	 * @param name
-	 *            The name of the sub-directory.
-	 * @return A handle to the newly-created directory.
-	 * @throws FilesystemAccessException
-	 *             If the name is the same as some existing entry in the
-	 *             directory, or if something else goes wrong during creation.
-	 */
-	Directory makeSubdirectory(Principal actor, String name)
-			throws FilesystemAccessException;
-
-	/**
-	 * Creates an empty file in this directory.
-	 * 
-	 * @param actor
-	 *            Who this is being created by.
-	 * @param name
-	 *            The name of the file to create.
-	 * @return A handle to the newly-created file.
-	 * @throws FilesystemAccessException
-	 *             If the name is the same as some existing entry in the
-	 *             directory, or if something else goes wrong during creation.
-	 */
-	File makeEmptyFile(Principal actor, String name)
-			throws FilesystemAccessException;
-
-	/**
-	 * A simple pipe that produces the zipped contents of a directory.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public static class ZipStream extends PipedInputStream {
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java
deleted file mode 100644
index e1a0865..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import java.util.Date;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-/**
- * An entry in a {@link Directory} representing a file or sub-directory.
- * 
- * @author Donal Fellows
- * @see Directory
- * @see File
- */
-public interface DirectoryEntry extends Comparable<DirectoryEntry> {
-	/**
-	 * @return The "local" name of the entry. This will never be "<tt>..</tt>"
-	 *         or contain the character "<tt>/</tt>".
-	 */
-	public String getName();
-
-	/**
-	 * @return The "full" name of the entry. This is computed relative to the
-	 *         workflow run's working directory. It may contain the "<tt>/</tt>"
-	 *         character.
-	 */
-	public String getFullName();
-
-	/**
-	 * @return The time that the entry was last modified.
-	 */
-	public Date getModificationDate();
-
-	/**
-	 * Destroy this directory entry, deleting the file or sub-directory. The
-	 * workflow run's working directory can never be manually destroyed.
-	 * 
-	 * @throws FilesystemAccessException
-	 *             If the destroy fails for some reason.
-	 */
-	public void destroy() throws FilesystemAccessException;
-	// TODO: Permissions (or decide not to do anything about them)
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java
deleted file mode 100644
index 97510e4..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-/**
- * Represents a file in the working directory of a workflow instance run, or in
- * some sub-directory of it.
- * 
- * @author Donal Fellows
- * @see Directory
- */
-public interface File extends DirectoryEntry {
-	/**
-	 * @param offset
-	 *            Where in the file to start reading.
-	 * @param length
-	 *            The length of file to read, or -1 to read to the end of the
-	 *            file.
-	 * @return The literal byte contents of the section of the file, or null if
-	 *         the section doesn't exist.
-	 * @throws FilesystemAccessException
-	 *             If the read of the file goes wrong.
-	 */
-	public byte[] getContents(int offset, int length)
-			throws FilesystemAccessException;
-
-	/**
-	 * 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 FilesystemAccessException
-	 *             If the write to the file goes wrong.
-	 */
-	public void setContents(byte[] data) throws FilesystemAccessException;
-
-	/**
-	 * Append the data to the file.
-	 * 
-	 * @param data
-	 *            The literal bytes that will be added on to the end of the
-	 *            file.
-	 * @throws FilesystemAccessException
-	 *             If the write to the file goes wrong.
-	 */
-	public void appendContents(byte[] data) throws FilesystemAccessException;
-
-	/**
-	 * @return The length of the file, in bytes.
-	 * @throws FilesystemAccessException
-	 *             If the read of the file size goes wrong.
-	 */
-	public long getSize() throws FilesystemAccessException;
-
-	/**
-	 * Asks for the argument file to be copied to this one.
-	 * 
-	 * @param from
-	 *            The source file.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	public void copy(File from) throws FilesystemAccessException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java
deleted file mode 100644
index 5d92f67..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-/**
- * 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 Input {
-	/**
-	 * @return The file currently assigned to this input port, or <tt>null</tt>
-	 *         if no file is assigned.
-	 */
-	@Nullable
-	public String getFile();
-
-	/**
-	 * @return The name of this input port. This may not be changed.
-	 */
-	@Nonnull
-	public String getName();
-
-	/**
-	 * @return The value currently assigned to this input port, or <tt>null</tt>
-	 *         if no value is assigned.
-	 */
-	@Nullable
-	public String getValue();
-
-	/**
-	 * @return The delimiter for the input port, or <tt>null</tt> if the value
-	 *         is not to be split.
-	 */
-	@Nullable
-	public String getDelimiter();
-
-	/**
-	 * 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 FilesystemAccessException
-	 *             If the filename is invalid.
-	 * @throws BadStateChangeException
-	 *             If the run isn't in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	public void setFile(String file) throws FilesystemAccessException,
-			BadStateChangeException;
-
-	/**
-	 * 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 BadStateChangeException
-	 *             If the run isn't in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	public void setValue(String value) throws BadStateChangeException;
-
-	/**
-	 * Sets (or clears) the delimiter for the input port.
-	 * 
-	 * @param delimiter
-	 *            The delimiter character, or <tt>null</tt> if the value is not
-	 *            to be split.
-	 * @throws BadStateChangeException
-	 *             If the run isn't in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	@Nullable
-	public void setDelimiter(String delimiter) throws BadStateChangeException;
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java
deleted file mode 100644
index 5fee6cc..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.NoListenerException;
-
-/**
- * An event listener that can be attached to a {@link TavernaRun}.
- * 
- * @author Donal Fellows
- */
-public interface Listener {
-	/**
-	 * @return The name of the listener.
-	 */
-	public String getName();
-
-	/**
-	 * @return The type of the listener.
-	 */
-	public String getType();
-
-	/**
-	 * @return The configuration document for the listener.
-	 */
-	public String getConfiguration();
-
-	/**
-	 * @return The supported properties of the listener.
-	 */
-	public String[] listProperties();
-
-	/**
-	 * 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 NoListenerException
-	 *             If no property with that name exists.
-	 */
-	public String getProperty(String propName) throws NoListenerException;
-
-	/**
-	 * 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 NoListenerException
-	 *             If no property with that name exists.
-	 * @throws BadPropertyValueException
-	 *             If the value of the property is bad (e.g., wrong syntax).
-	 */
-	public void setProperty(String propName, String value)
-			throws NoListenerException, BadPropertyValueException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java
deleted file mode 100644
index becc55c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * This interface describes how to map from the identity understood by the
- * webapp to the identity understood by the local execution system.
- * 
- * @author Donal Fellows
- */
-public interface LocalIdentityMapper {
-	/**
-	 * Given a user's identity, get the local identity to use for executing
-	 * their workflows. Note that it is assumed that there will never be a
-	 * failure from this interface; it is <i>not</i> a security policy
-	 * decision or enforcement point.
-	 * 
-	 * @param user
-	 *            An identity token.
-	 * @return A user name, which must be defined in the context that workflows
-	 *         will be running in.
-	 */
-	public String getUsernameForPrincipal(UsernamePrincipal user);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java
deleted file mode 100644
index b3e0260..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import javax.annotation.Nonnull;
-
-/**
- * The interface supported by all notification message dispatchers.
- * @author Donal Fellows
- */
-public interface MessageDispatcher {
-	/**
-	 * @return Whether this message dispatcher is actually available (fully
-	 *         configured, etc.)
-	 */
-	boolean isAvailable();
-
-	/**
-	 * @return The name of this dispatcher, which must match the protocol
-	 *         supported by it (for a non-universal dispatcher) and the name of
-	 *         the message generator used to produce the message.
-	 */
-	String getName();
-
-	/**
-	 * Dispatch a message to a recipient.
-	 * 
-	 * @param originator
-	 *            The workflow run that produced the message.
-	 * @param messageSubject
-	 *            The subject of the message to send.
-	 * @param messageContent
-	 *            The plain-text content of the message to send.
-	 * @param targetParameter
-	 *            A description of where it is to go.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	void dispatch(@Nonnull TavernaRun originator,
-			@Nonnull String messageSubject, @Nonnull String messageContent,
-			@Nonnull String targetParameter) throws Exception;
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java
deleted file mode 100644
index b09e0bd..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import java.net.URI;
-import java.util.List;
-
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Simple policy interface.
- * 
- * @author Donal Fellows
- */
-public interface Policy {
-	/**
-	 * @return The maximum number of runs that the system can support.
-	 */
-	int getMaxRuns();
-
-	/**
-	 * Get the limit on the number of runs for this user.
-	 * 
-	 * @param user
-	 *            Who to get the limit for
-	 * @return The maximum number of runs for this user, or <tt>null</tt> if no
-	 *         per-user limit is imposed and only system-wide limits are to be
-	 *         enforced.
-	 */
-	Integer getMaxRuns(UsernamePrincipal user);
-
-	/**
-	 * Test whether the user can create an instance of the given workflow.
-	 * 
-	 * @param user
-	 *            Who wants to do the creation.
-	 * @param workflow
-	 *            The workflow they wish to instantiate.
-	 * @throws NoCreateException
-	 *             If they may not instantiate it.
-	 */
-	void permitCreate(UsernamePrincipal user, Workflow workflow)
-			throws NoCreateException;
-
-	/**
-	 * Test whether the user can destroy a workflow instance run or manipulate
-	 * its expiry date.
-	 * 
-	 * @param user
-	 *            Who wants to do the deletion.
-	 * @param run
-	 *            What they want to delete.
-	 * @throws NoDestroyException
-	 *             If they may not destroy it.
-	 */
-	void permitDestroy(UsernamePrincipal user, TavernaRun run)
-			throws NoDestroyException;
-
-	/**
-	 * Return whether the user has access to a particular workflow run.
-	 * <b>Note</b> that this does not throw any exceptions!
-	 * 
-	 * @param user
-	 *            Who wants to read the workflow's state.
-	 * @param run
-	 *            What do they want to read from.
-	 * @return Whether they can read it. Note that this check is always applied
-	 *         before testing whether the workflow can be updated or deleted by
-	 *         the user.
-	 */
-	boolean permitAccess(UsernamePrincipal user, TavernaRun run);
-
-	/**
-	 * Test whether the user can modify a workflow run (other than for its
-	 * expiry date).
-	 * 
-	 * @param user
-	 *            Who wants to do the modification.
-	 * @param run
-	 *            What they want to modify.
-	 * @throws NoUpdateException
-	 *             If they may not modify it.
-	 */
-	void permitUpdate(UsernamePrincipal user, TavernaRun run)
-			throws NoUpdateException;
-
-	/**
-	 * Get the URIs of the workflows that the given user may execute.
-	 * 
-	 * @param user
-	 *            Who are we finding out on behalf of.
-	 * @return A list of workflow URIs that they may instantiate, or
-	 *         <tt>null</tt> if any workflow may be submitted.
-	 */
-	List<URI> listPermittedWorkflowURIs(UsernamePrincipal user);
-
-	/**
-	 * @return The maximum number of {@linkplain Status#Operating operating}
-	 *         runs that the system can support.
-	 */
-	int getOperatingLimit();
-
-	/**
-	 * Set the URIs of the workflows that the given user may execute.
-	 * 
-	 * @param user
-	 *            Who are we finding out on behalf of.
-	 * @param permitted
-	 *            A list of workflow URIs that they may instantiate.
-	 */
-	void setPermittedWorkflowURIs(UsernamePrincipal user, List<URI> permitted);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java
deleted file mode 100644
index b0d817a..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import java.util.Map;
-
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Interface to the mechanism that looks after the mapping of names to runs.
- * Instances of this class may also be responsible for enforcing timely cleanup
- * of expired workflows.
- * 
- * @author Donal Fellows.
- */
-public interface RunStore {
-	/**
-	 * Obtain the workflow run for a given user and name.
-	 * 
-	 * @param user
-	 *            Who wants to do the lookup.
-	 * @param p
-	 *            The general policy system context.
-	 * @param uuid
-	 *            The handle for the run.
-	 * @return The workflow instance run.
-	 * @throws UnknownRunException
-	 *             If the lookup fails (either because it does not exist or
-	 *             because it is not permitted for the user by the policy).
-	 */
-	TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
-			throws UnknownRunException;
-
-	/**
-	 * Obtain the named workflow run.
-	 * 
-	 * @param uuid
-	 *            The handle for the run.
-	 * @return The workflow instance run.
-	 * @throws UnknownRunException
-	 *             If the lookup fails (either because it does not exist or
-	 *             because it is not permitted for the user by the policy).
-	 */
-	public TavernaRun getRun(String uuid) throws UnknownRunException;
-
-	/**
-	 * List the runs that a particular user may access.
-	 * 
-	 * @param user
-	 *            Who wants to do the lookup, or <code>null</code> if it is
-	 *            being done "by the system" when the full mapping should be
-	 *            returned.
-	 * @param p
-	 *            The general policy system context.
-	 * @return A mapping from run names to run instances.
-	 */
-	Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p);
-
-	/**
-	 * Adds a workflow instance run to the store. Note that this operation is
-	 * <i>not</i> expected to be security-checked; that is the callers'
-	 * responsibility.
-	 * 
-	 * @param run
-	 *            The run itself.
-	 * @return The name of the run.
-	 */
-	String registerRun(TavernaRun run);
-
-	/**
-	 * Removes a run from the store. Note that this operation is <i>not</i>
-	 * expected to be security-checked; that is the callers' responsibility.
-	 * 
-	 * @param uuid
-	 *            The name of the run.
-	 */
-	void unregisterRun(String uuid);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java
deleted file mode 100644
index a0cac79..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import java.io.Serializable;
-
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * How to create instances of a security context.
- * 
- * @author Donal Fellows
- */
-public interface SecurityContextFactory extends Serializable {
-	/**
-	 * Creates a security context.
-	 * 
-	 * @param run
-	 *            Handle to remote run. Allows the security context to know how
-	 *            to apply itself to the workflow run.
-	 * @param owner
-	 *            The identity of the owner of the workflow run.
-	 * @return The security context.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	TavernaSecurityContext create(TavernaRun run, UsernamePrincipal owner)
-			throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java
deleted file mode 100644
index 8d9a7f8..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import java.io.Serializable;
-import java.util.Date;
-import java.util.List;
-
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-
-/**
- * The interface to a taverna workflow run, or "run" for short.
- * 
- * @author Donal Fellows
- */
-public interface TavernaRun extends Serializable {
-	/**
-	 * @return The identifier of the run.
-	 */
-	String getId();
-
-	/**
-	 * @return What was this run was create to execute.
-	 */
-	Workflow getWorkflow();
-
-	/**
-	 * @return The name of the run.
-	 */
-	String getName();
-
-	/**
-	 * @param name
-	 *            The new name of the run. May be truncated.
-	 */
-	void setName(String name);
-
-	/**
-	 * @return The name of the Baclava file to use for all inputs, or
-	 *         <tt>null</tt> if no Baclava file is set.
-	 */
-	String getInputBaclavaFile();
-
-	/**
-	 * 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 FilesystemAccessException
-	 *             If the filename is invalid.
-	 * @throws BadStateChangeException
-	 *             If the workflow is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	void setInputBaclavaFile(String filename) throws FilesystemAccessException,
-			BadStateChangeException;
-
-	/**
-	 * @return The list of input assignments.
-	 */
-	List<Input> getInputs();
-
-	/**
-	 * Create an input assignment.
-	 * 
-	 * @param name
-	 *            The name of the port that this will be an input for.
-	 * @return The assignment reference.
-	 * @throws BadStateChangeException
-	 *             If the workflow is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	Input makeInput(String name) throws BadStateChangeException;
-
-	/**
-	 * @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>.
-	 */
-	String getOutputBaclavaFile();
-
-	/**
-	 * 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 FilesystemAccessException
-	 *             If the filename starts with a <tt>/</tt> or contains a
-	 *             <tt>..</tt> segment.
-	 * @throws BadStateChangeException
-	 *             If the workflow is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	void setOutputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException;
-
-	/**
-	 * @return When this run will expire, becoming eligible for automated
-	 *         deletion.
-	 */
-	Date getExpiry();
-
-	/**
-	 * Set when this run will expire.
-	 * 
-	 * @param d
-	 *            Expiry time. Deletion will happen some time after that.
-	 */
-	void setExpiry(Date d);
-
-	/**
-	 * @return The current status of the run.
-	 */
-	Status getStatus();
-
-	/**
-	 * 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.
-	 * @return <tt>null</tt>, or a string describing the incomplete state change
-	 *         if the operation has internally timed out.
-	 * @throws BadStateChangeException
-	 *             If the change to the given state is impossible.
-	 */
-	String setStatus(Status s) throws BadStateChangeException;
-
-	/**
-	 * @return Handle to the main working directory of the run.
-	 * @throws FilesystemAccessException
-	 */
-	Directory getWorkingDirectory() throws FilesystemAccessException;
-
-	/**
-	 * @return The list of listener instances attached to the run.
-	 */
-	List<Listener> getListeners();
-
-	/**
-	 * Add a listener to the run.
-	 * 
-	 * @param listener
-	 *            The listener to add.
-	 */
-	void addListener(Listener listener);
-
-	/**
-	 * @return The security context structure for this run.
-	 */
-	TavernaSecurityContext getSecurityContext();
-
-	/**
-	 * Kill off this run, removing all resources which it consumes.
-	 * 
-	 * @throws NoDestroyException
-	 *             If the destruction failed.
-	 */
-	void destroy() throws NoDestroyException;
-
-	/**
-	 * @return When this workflow run was created.
-	 */
-	Date getCreationTimestamp();
-
-	/**
-	 * @return When this workflow run was started, or <tt>null</tt> if it has
-	 *         never been started.
-	 */
-	Date getStartTimestamp();
-
-	/**
-	 * @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).
-	 */
-	Date getFinishTimestamp();
-
-	/**
-	 * Test if this run is really there.
-	 * 
-	 * <p>
-	 * <i>Implementation note:</i> Used to test communication fabrics, etc. so
-	 * implementations of this interface that do not delegate to another object
-	 * should do nothing.
-	 * 
-	 * @throws UnknownRunException
-	 *             If things fail.
-	 */
-	void ping() throws UnknownRunException;
-
-	/**
-	 * @return whether the run generates provenance data
-	 */
-	boolean getGenerateProvenance();
-
-	/**
-	 * @param generateProvenance
-	 *            whether the run generates provenance data
-	 */
-	void setGenerateProvenance(boolean generateProvenance);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java
deleted file mode 100644
index 3f993df..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.security.Principal;
-import java.util.Set;
-
-import javax.ws.rs.core.HttpHeaders;
-import javax.xml.ws.handler.MessageContext;
-
-import org.springframework.security.core.context.SecurityContext;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Security context for a workflow run.
- * 
- * @author Donal Fellows
- */
-public interface TavernaSecurityContext {
-	/**
-	 * @return Who owns the security context.
-	 */
-	UsernamePrincipal getOwner();
-
-	/**
-	 * Describe the names of the users (as extracted from their
-	 * {@link Principal} objects) that may destroy the run or manipulate its
-	 * lifetime.
-	 * 
-	 * @return The names of the users who may use destroy operations. Read-only.
-	 */
-	Set<String> getPermittedDestroyers();
-
-	/**
-	 * Sets the collection of names of users (as extracted from their
-	 * {@link Principal} objects) that may destroy the run or manipulate its
-	 * lifetime.
-	 * 
-	 * @param destroyers
-	 *            The names of the users who may use destroy operations.
-	 */
-	void setPermittedDestroyers(Set<String> destroyers);
-
-	/**
-	 * Describe the names of the users (as extracted from their
-	 * {@link Principal} objects) that may update the run (including writing to
-	 * files).
-	 * 
-	 * @return The names of the users who may use update operations. Read-only.
-	 */
-	Set<String> getPermittedUpdaters();
-
-	/**
-	 * Sets the collection of names of users (as extracted from their
-	 * {@link Principal} objects) that may update the run (including writing to
-	 * its files).
-	 * 
-	 * @param updaters
-	 *            The names of the users who may use update operations.
-	 */
-	void setPermittedUpdaters(Set<String> updaters);
-
-	/**
-	 * Describe the names of the users (as extracted from their
-	 * {@link Principal} objects) that may read from the run (including its
-	 * files).
-	 * 
-	 * @return The names of the users who may use read operations. Read-only.
-	 */
-	Set<String> getPermittedReaders();
-
-	/**
-	 * Sets the collection of names of users (as extracted from their
-	 * {@link Principal} objects) that may read from the run (including its
-	 * files).
-	 * 
-	 * @param readers
-	 *            The names of the users who may use read operations.
-	 */
-	void setPermittedReaders(Set<String> readers);
-
-	/**
-	 * @return The credentials owned by the user. Never <tt>null</tt>.
-	 */
-	Credential[] getCredentials();
-
-	/**
-	 * Add a credential to the owned set or replaces the old version with the
-	 * new one.
-	 * 
-	 * @param toAdd
-	 *            The credential to add.
-	 */
-	void addCredential(Credential toAdd);
-
-	/**
-	 * Remove a credential from the owned set. It's not a failure to remove
-	 * something that isn't in the set.
-	 * 
-	 * @param toDelete
-	 *            The credential to remove.
-	 */
-	void deleteCredential(Credential toDelete);
-
-	/**
-	 * Tests if the credential is valid. This includes testing whether the
-	 * underlying credential file exists and can be unlocked by the password in
-	 * the {@link Credential} object.
-	 * 
-	 * @param c
-	 *            The credential object to validate.
-	 * @throws InvalidCredentialException
-	 *             If it is invalid.
-	 */
-	void validateCredential(Credential c) throws InvalidCredentialException;
-
-	/**
-	 * @return The identities trusted by the user. Never <tt>null</tt>.
-	 */
-	Trust[] getTrusted();
-
-	/**
-	 * Add an identity to the trusted set.
-	 * 
-	 * @param toAdd
-	 *            The identity to add.
-	 */
-	void addTrusted(Trust toAdd);
-
-	/**
-	 * Remove an identity from the trusted set. It's not a failure to remove
-	 * something that isn't in the set.
-	 * 
-	 * @param toDelete
-	 *            The identity to remove.
-	 */
-	void deleteTrusted(Trust toDelete);
-
-	/**
-	 * Tests if the trusted identity descriptor is valid. This includes checking
-	 * whether the underlying trusted identity file exists.
-	 * 
-	 * @param t
-	 *            The trusted identity descriptor to check.
-	 * @throws InvalidCredentialException
-	 *             If it is invalid.
-	 */
-	void validateTrusted(Trust t) throws InvalidCredentialException;
-
-	/**
-	 * Establish the security context from how the owning workflow run was
-	 * created. In particular, this gives an opportunity for boot-strapping
-	 * things with any delegateable credentials.
-	 * 
-	 * @param securityContext
-	 *            The security context associated with the request that caused
-	 *            the workflow to be created.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	void initializeSecurityFromContext(SecurityContext securityContext)
-			throws Exception;
-
-	/**
-	 * Establish the security context from how the owning workflow run was
-	 * created. In particular, this gives an opportunity for boot-strapping
-	 * things with any delegateable credentials.
-	 * 
-	 * @param context
-	 *            The full information about the request that caused the
-	 *            workflow to be created.
-	 */
-	void initializeSecurityFromSOAPContext(MessageContext context);
-
-	/**
-	 * Establish the security context from how the owning workflow run was
-	 * created. In particular, this gives an opportunity for boot-strapping
-	 * things with any delegateable credentials.
-	 * 
-	 * @param headers
-	 *            The full information about the request that caused the
-	 *            workflow to be created.
-	 */
-	void initializeSecurityFromRESTContext(HttpHeaders headers);
-
-	/**
-	 * Transfer the security context to the remote system.
-	 * 
-	 * @throws IOException
-	 *             If the communication fails.
-	 * @throws GeneralSecurityException
-	 *             If the assembly of the context fails.
-	 * @throws ImplementationException
-	 *             If the local worker has problems with creating the realized
-	 *             security context.
-	 */
-	void conveySecurity() throws GeneralSecurityException, IOException,
-			ImplementationException;
-
-	/**
-	 * @return The factory that created this security context.
-	 */
-	SecurityContextFactory getFactory();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java
deleted file mode 100644
index c4d0fb5..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */
-
-import java.net.URI;
-
-import javax.ws.rs.core.UriBuilder;
-
-/**
- * How to manufacture URIs to workflow runs.
- * 
- * @author Donal Fellows
- */
-public interface UriBuilderFactory {
-	/**
-	 * Given a run, get a factory for RESTful URIs to resources associated
-	 * with it.
-	 * 
-	 * @param run
-	 *            The run in question.
-	 * @return The {@link URI} factory.
-	 */
-	UriBuilder getRunUriBuilder(TavernaRun run);
-
-	/**
-	 * @return a URI factory that is preconfigured to point to the base of
-	 *         the webapp.
-	 */
-	UriBuilder getBaseUriBuilder();
-
-	/**
-	 * Resolves a URI with respect to the base URI of the factory.
-	 * 
-	 * @param uri
-	 *            The URI to resolve, or <tt>null</tt>.
-	 * @return The resolved URI, or <tt>null</tt> if <b>uri</b> is
-	 *         <tt>null</tt>.
-	 */
-	String resolve(String uri);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java
deleted file mode 100644
index 9c9b5b8..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-/**
- * Interfaces to the main worker classes that provide the magical power
- * that drives the webapp front-end.
- */
-package org.taverna.server.master.interfaces;
-/*
- * 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.
- */


[25/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerRunREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerRunREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerRunREST.java
new file mode 100644
index 0000000..ef6ddd4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerRunREST.java
@@ -0,0 +1,810 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.joda.time.format.ISODateTimeFormat.basicDateTime;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
+import static org.taverna.server.master.interaction.InteractionFeedSupport.FEED_URL_DIR;
+import static org.taverna.server.master.rest.ContentTypes.JSON;
+import static org.taverna.server.master.rest.ContentTypes.ROBUNDLE;
+import static org.taverna.server.master.rest.ContentTypes.TEXT;
+import static org.taverna.server.master.rest.ContentTypes.XML;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.GENERATE_PROVENANCE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.IN;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LISTEN;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LOG;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.NAME;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.OUT;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.PROFILE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.ROOT;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.RUNBUNDLE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.SEC;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STATUS;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDERR;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDOUT;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_CREATE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_EXPIRE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_FINISH;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_START;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.USAGE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.WF;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.JAXBException;
+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;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.joda.time.format.DateTimeFormatter;
+import org.taverna.server.master.common.Namespaces;
+import org.taverna.server.master.common.ProfileList;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Uri;
+import org.taverna.server.master.common.VersionedElement;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.exceptions.NotOwnerException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.port_description.OutputDescription;
+
+/**
+ * This represents how a Taverna Server workflow run looks to a RESTful API.
+ * 
+ * @author Donal Fellows.
+ */
+@Description("This represents how a Taverna Server workflow run looks to a "
+		+ "RESTful API.")
+@RolesAllowed(USER)
+public interface TavernaServerRunREST {
+	/**
+	 * Describes a workflow run.
+	 * 
+	 * @param ui
+	 *            About the URI used to access this resource.
+	 * @return The description.
+	 */
+	@GET
+	@Path(ROOT)
+	@Description("Describes a workflow run.")
+	@Produces({ XML, JSON })
+	@Nonnull
+	public RunDescription getDescription(@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Deletes a workflow run.
+	 * 
+	 * @return An HTTP response to the deletion.
+	 * @throws NoUpdateException
+	 *             If the user may see the handle but may not delete it.
+	 */
+	@DELETE
+	@Path(ROOT)
+	@Description("Deletes a workflow run.")
+	@Nonnull
+	public Response destroy() throws NoUpdateException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ROOT)
+	@Description("Produces the description of the run.")
+	Response runOptions();
+
+	/**
+	 * Returns the workflow document used to create the workflow run.
+	 * 
+	 * @return The workflow document.
+	 */
+	@GET
+	@Path(WF)
+	@Produces({ T2FLOW, SCUFL2, XML, JSON })
+	@Description("Gives the workflow document used to create the workflow run.")
+	@Nonnull
+	public Workflow getWorkflow();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(WF)
+	@Description("Produces the description of the run workflow.")
+	Response workflowOptions();
+
+	/** Get the workflow name. */
+	@GET
+	@Path(NAME)
+	@Produces(TEXT)
+	@Description("Gives the descriptive name of the workflow run.")
+	@Nonnull
+	public String getName();
+
+	/**
+	 * Set the workflow name.
+	 * 
+	 * @throws NoUpdateException
+	 *             If the user is not permitted to change the workflow.
+	 */
+	@PUT
+	@Path(NAME)
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Description("Set the descriptive name of the workflow run. Note that "
+			+ "this value may be arbitrarily truncated by the implementation.")
+	@Nonnull
+	public String setName(String name) throws NoUpdateException;
+
+	/** Produce the workflow name HTTP operations. */
+	@OPTIONS
+	@Path(NAME)
+	@Description("Produces the description of the operations on the run's "
+			+ "descriptive name.")
+	@Nonnull
+	Response nameOptions();
+
+	/**
+	 * Produces the name of the workflow's main profile.
+	 * 
+	 * @return The main profile name, or the empty string if there is no such
+	 *         profile.
+	 */
+	@GET
+	@Path(PROFILE)
+	@Produces(TEXT)
+	@Description("Gives the name of the workflow's main profile, or the empty string if none is defined.")
+	@Nonnull
+	String getMainProfileName();
+
+	/**
+	 * Get a description of the profiles supported by the workflow document used
+	 * to create this run.
+	 * 
+	 * @return A description of the supported profiles.
+	 */
+	@GET
+	@Path(PROFILE)
+	@Produces({ XML, JSON })
+	@Description("Describes what profiles exist on the workflow.")
+	@Nonnull
+	ProfileList getProfiles();
+
+	/** Produce the workflow profile HTTP operations. */
+	@OPTIONS
+	@Path(PROFILE)
+	@Description("Produces the description of the operations on the run's "
+			+ "profile.")
+	@Nonnull
+	Response profileOptions();
+
+	/**
+	 * Returns a resource that represents the workflow run's security
+	 * properties. These may only be accessed by the owner.
+	 * 
+	 * @return The security resource.
+	 * @throws NotOwnerException
+	 *             If the accessing principal isn't the owning principal.
+	 */
+	@Path(SEC)
+	@Description("Access the workflow run's security.")
+	@Nonnull
+	public TavernaServerSecurityREST getSecurity() throws NotOwnerException;
+
+	/**
+	 * Returns the time when the workflow run becomes eligible for automatic
+	 * deletion.
+	 * 
+	 * @return When the run expires.
+	 */
+	@GET
+	@Path(T_EXPIRE)
+	@Produces(TEXT)
+	@Description("Gives the time when the workflow run becomes eligible for "
+			+ "automatic deletion.")
+	@Nonnull
+	public String getExpiryTime();
+
+	/**
+	 * Sets the time when the workflow run becomes eligible for automatic
+	 * deletion.
+	 * 
+	 * @param expiry
+	 *            When the run will expire.
+	 * @return When the run will actually expire.
+	 * @throws NoUpdateException
+	 *             If the current user is not permitted to manage the lifetime
+	 *             of the run.
+	 */
+	@PUT
+	@Path(T_EXPIRE)
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Description("Sets the time when the workflow run becomes eligible for "
+			+ "automatic deletion.")
+	@Nonnull
+	public String setExpiryTime(@Nonnull String expiry)
+			throws NoUpdateException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(T_EXPIRE)
+	@Description("Produces the description of the run expiry.")
+	Response expiryOptions();
+
+	/**
+	 * Returns the time when the workflow run was created.
+	 * 
+	 * @return When the run was first submitted to the server.
+	 */
+	@GET
+	@Path(T_CREATE)
+	@Produces(TEXT)
+	@Description("Gives the time when the workflow run was first submitted "
+			+ "to the server.")
+	@Nonnull
+	public String getCreateTime();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(T_CREATE)
+	@Description("Produces the description of the run create time.")
+	Response createTimeOptions();
+
+	/**
+	 * Returns the time when the workflow run was started (through a user-driven
+	 * state change).
+	 * 
+	 * @return When the run was started, or <tt>null</tt>.
+	 */
+	@GET
+	@Path(T_START)
+	@Produces(TEXT)
+	@Description("Gives the time when the workflow run was started, or an "
+			+ "empty string if the run has not yet started.")
+	@Nonnull
+	public String getStartTime();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(T_START)
+	@Description("Produces the description of the run start time.")
+	Response startTimeOptions();
+
+	/**
+	 * Returns the time when the workflow run was detected to have finished.
+	 * 
+	 * @return When the run finished, or <tt>null</tt>.
+	 */
+	@GET
+	@Path(T_FINISH)
+	@Produces(TEXT)
+	@Description("Gives the time when the workflow run was first detected as "
+			+ "finished, or an empty string if it has not yet finished "
+			+ "(including if it has never started).")
+	@Nonnull
+	public String getFinishTime();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(T_FINISH)
+	@Description("Produces the description of the run finish time.")
+	Response finishTimeOptions();
+
+	/**
+	 * Gets the current status of the workflow run.
+	 * 
+	 * @return The status code.
+	 */
+	@GET
+	@Path(STATUS)
+	@Produces(TEXT)
+	@Description("Gives the current status of the workflow run.")
+	@Nonnull
+	public String getStatus();
+
+	/**
+	 * Sets the status of the workflow run. This does nothing if the status code
+	 * is the same as the run's current state.
+	 * 
+	 * @param status
+	 *            The new status code.
+	 * @return Description of what status the run is actually in, or a 202 to
+	 *         indicate that things are still changing.
+	 * @throws NoUpdateException
+	 *             If the current user is not permitted to update the run.
+	 * @throws BadStateChangeException
+	 *             If the state cannot be modified in the manner requested.
+	 */
+	@PUT
+	@Path(STATUS)
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Description("Attempts to update the status of the workflow run.")
+	@Nonnull
+	public Response setStatus(@Nonnull String status) throws NoUpdateException,
+			BadStateChangeException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(STATUS)
+	@Description("Produces the description of the run status.")
+	Response statusOptions();
+
+	/**
+	 * Get the working directory of this workflow run.
+	 * 
+	 * @return A RESTful delegate for the working directory.
+	 */
+	@Path(DIR)
+	@Description("Get the working directory of this workflow run.")
+	@Nonnull
+	public TavernaServerDirectoryREST getWorkingDirectory();
+
+	/**
+	 * Get the event listeners attached to this workflow run.
+	 * 
+	 * @return A RESTful delegate for the list of listeners.
+	 */
+	@Path(LISTEN)
+	@Description("Get the event listeners attached to this workflow run.")
+	@Nonnull
+	public TavernaServerListenersREST getListeners();
+
+	/**
+	 * Get a delegate for working with the inputs to this workflow run.
+	 * 
+	 * @param ui
+	 *            About the URI used to access this resource.
+	 * @return A RESTful delegate for the inputs.
+	 */
+	@Path(IN)
+	@Description("Get the inputs to this workflow run.")
+	@Nonnull
+	public TavernaServerInputREST getInputs(@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Get the output Baclava file for this workflow run.
+	 * 
+	 * @return The filename, or empty string to indicate that the outputs will
+	 *         be written to the <tt>out</tt> directory.
+	 */
+	@GET
+	@Path(OUT)
+	@Produces(TEXT)
+	@Description("Gives the Baclava file where output will be written; empty "
+			+ "means use multiple simple files in the out directory.")
+	@Nonnull
+	public String getOutputFile();
+
+	/**
+	 * Get a description of the outputs.
+	 * 
+	 * @param ui
+	 *            About the URI used to access this operation.
+	 * @return A description of the outputs (higher level than the filesystem).
+	 * @throws BadStateChangeException
+	 *             If the run is in the {@link Status#Initialized Initialized}
+	 *             state.
+	 * @throws FilesystemAccessException
+	 *             If problems occur when accessing the filesystem.
+	 * @throws NoDirectoryEntryException
+	 *             If things are odd in the filesystem.
+	 */
+	@GET
+	@Path(OUT)
+	@Produces({ XML, JSON })
+	@Description("Gives a description of the outputs, as currently understood")
+	@Nonnull
+	public OutputDescription getOutputDescription(@Nonnull @Context UriInfo ui)
+			throws BadStateChangeException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Set the output Baclava file for this workflow run.
+	 * 
+	 * @param filename
+	 *            The Baclava file to use, or empty to make the outputs be
+	 *            written to individual files in the <tt>out</tt> subdirectory
+	 *            of the working directory.
+	 * @return The Baclava file as actually set.
+	 * @throws NoUpdateException
+	 *             If the current user is not permitted to update the run.
+	 * @throws FilesystemAccessException
+	 *             If the filename is invalid (starts with <tt>/</tt> or
+	 *             contains a <tt>..</tt> segment).
+	 * @throws BadStateChangeException
+	 *             If the workflow is not in the Initialized state.
+	 */
+	@PUT
+	@Path(OUT)
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Description("Sets the Baclava file where output will be written; empty "
+			+ "means use multiple simple files in the out directory.")
+	@Nonnull
+	public String setOutputFile(@Nonnull String filename)
+			throws NoUpdateException, FilesystemAccessException,
+			BadStateChangeException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(OUT)
+	@Description("Produces the description of the run output.")
+	Response outputOptions();
+
+	/**
+	 * Get a handle to the interaction feed.
+	 * 
+	 * @return
+	 */
+	@Path(FEED_URL_DIR)
+	@Description("Access the interaction feed for the workflow run.")
+	@Nonnull
+	InteractionFeedREST getInteractionFeed();
+
+	/**
+	 * @return The stdout for the workflow run, or empty string if the run has
+	 *         not yet started.
+	 * @throws NoListenerException
+	 */
+	@GET
+	@Path(STDOUT)
+	@Description("Return the stdout for the workflow run.")
+	@Produces(TEXT)
+	@Nonnull
+	String getStdout() throws NoListenerException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(STDOUT)
+	@Description("Return the stdout for the workflow run.")
+	Response stdoutOptions();
+
+	/**
+	 * @return The stderr for the workflow run, or empty string if the run has
+	 *         not yet started.
+	 * @throws NoListenerException
+	 */
+	@GET
+	@Path(STDERR)
+	@Description("Return the stderr for the workflow run.")
+	@Produces(TEXT)
+	@Nonnull
+	String getStderr() throws NoListenerException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(STDERR)
+	@Description("Return the stderr for the workflow run.")
+	Response stderrOptions();
+
+	/**
+	 * @return The usage record for the workflow run, wrapped in a Response, or
+	 *         "empty content" if the run has not yet finished.
+	 * @throws NoListenerException
+	 * @throws JAXBException
+	 */
+	@GET
+	@Path(USAGE)
+	@Description("Return the usage record for the workflow run.")
+	@Produces(XML)
+	@Nonnull
+	Response getUsage() throws NoListenerException, JAXBException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(USAGE)
+	@Description("Return the usage record for the workflow run.")
+	Response usageOptions();
+
+	/**
+	 * @return The log for the workflow run, or empty string if the run has not
+	 *         yet started.
+	 */
+	@GET
+	@Path(LOG)
+	@Description("Return the log for the workflow run.")
+	@Produces(TEXT)
+	@Nonnull
+	Response getLogContents();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(LOG)
+	@Description("Return the log for the workflow run.")
+	Response logOptions();
+
+	/**
+	 * @return The log for the workflow run, or empty string if the run has not
+	 *         yet started.
+	 */
+	@GET
+	@Path(RUNBUNDLE)
+	@Description("Return the run bundle for the workflow run.")
+	@Produces(ROBUNDLE)
+	@Nonnull
+	Response getRunBundle();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(RUNBUNDLE)
+	@Description("Return the run bundle for the workflow run.")
+	Response runBundleOptions();
+
+	/**
+	 * @return Whether to create the run bundle for the workflow run. Only
+	 *         usefully set-able before the start of the run.
+	 */
+	@GET
+	@Path(GENERATE_PROVENANCE)
+	@Description("Whether to create the run bundle for the workflow run.")
+	@Produces(TEXT)
+	@Nonnull
+	boolean getGenerateProvenance();
+
+	/**
+	 * @param provenanceFlag
+	 *            Whether to create the run bundle for the workflow run. Only
+	 *            usefully set-able before the start of the run.
+	 * @return What it was actually set to.
+	 * @throws NoUpdateException 
+	 */
+	@PUT
+	@Path(GENERATE_PROVENANCE)
+	@Description("Whether to create the run bundle for the workflow run.")
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Nonnull
+	boolean setGenerateProvenance(boolean provenanceFlag) throws NoUpdateException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(GENERATE_PROVENANCE)
+	@Description("Whether to create the run bundle for the workflow run.")
+	Response generateProvenanceOptions();
+
+	/**
+	 * Factored out path names used in the {@link TavernaServerRunREST}
+	 * interface and related places.
+	 * 
+	 * @author Donal Fellows
+	 */
+	interface PathNames {
+		public static final String ROOT = "/";
+		public static final String WF = "workflow";
+		public static final String DIR = "wd";
+		public static final String NAME = "name";
+		public static final String T_EXPIRE = "expiry";
+		public static final String T_CREATE = "createTime";
+		public static final String T_START = "startTime";
+		public static final String T_FINISH = "finishTime";
+		public static final String STATUS = "status";
+		public static final String IN = "input";
+		public static final String OUT = "output";
+		public static final String PROFILE = "profile";
+		public static final String LISTEN = "listeners";
+		public static final String SEC = "security";
+		public static final String STDOUT = "stdout";
+		public static final String STDERR = "stderr";
+		public static final String USAGE = "usage";
+		public static final String LOG = "log";
+		public static final String RUNBUNDLE = "run-bundle";
+		public static final String GENERATE_PROVENANCE = "generate-provenance";
+	}
+
+	/**
+	 * The description of where everything is in a RESTful view of a workflow
+	 * run. Done with JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "")
+	public static class RunDescription extends VersionedElement {
+		/** The identity of the owner of the workflow run. */
+		@XmlAttribute(namespace = Namespaces.SERVER_REST)
+		public String owner;
+		/** The description of the expiry. */
+		public Expiry expiry;
+		/** The location of the creation workflow description. */
+		public Uri creationWorkflow;
+		/** The location of the creation time property. */
+		public Uri createTime;
+		/** The location of the start time property. */
+		public Uri startTime;
+		/** The location of the finish time property. */
+		public Uri finishTime;
+		/** The location of the status description. */
+		public Uri status;
+		/** The location of the working directory. */
+		public Uri workingDirectory;
+		/** The location of the inputs. */
+		public Uri inputs;
+		/** The location of the Baclava output. */
+		public Uri output;
+		/** The location of the security context. */
+		public Uri securityContext;
+		/** The list of listeners. */
+		public ListenerList listeners;
+		/** The location of the interaction feed. */
+		public Uri interaction;
+		/** The name of the run. */
+		public Uri name;
+		/** The stdout of the run. */
+		public Uri stdout;
+		/** The stderr of the run. */
+		public Uri stderr;
+		/** The usage record for the run. */
+		public Uri usage;
+		/** The log from the run. */
+		public Uri log;
+		/** The bundle describing the run. */
+		@XmlElement(name = RUNBUNDLE)
+		public Uri runBundle;
+		/** Whether to generate a bundle describing the run. */
+		@XmlElement(name = GENERATE_PROVENANCE)
+		public Uri generateProvenance;
+
+		/**
+		 * How to describe a run's expiry.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "")
+		public static class Expiry {
+			/**
+			 * Where to go to read the exiry
+			 */
+			@XmlAttribute(name = "href", namespace = Namespaces.XLINK)
+			@XmlSchemaType(name = "anyURI")
+			public URI ref;
+			/**
+			 * What the expiry currently is.
+			 */
+			@XmlValue
+			public String timeOfDeath;
+
+			/**
+			 * Make a blank expiry description.
+			 */
+			public Expiry() {
+			}
+
+			private static DateTimeFormatter dtf;
+
+			Expiry(TavernaRun r, UriInfo ui, String path, String... parts) {
+				ref = fromUri(new Uri(ui, true, path, parts).ref).build();
+				if (dtf == null)
+					dtf = basicDateTime();
+				timeOfDeath = dtf.print(r.getExpiry().getTime());
+			}
+		}
+
+		/**
+		 * The description of a list of listeners attached to a run.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "")
+		public static class ListenerList extends Uri {
+			/**
+			 * The references to the individual listeners.
+			 */
+			public List<Uri> listener;
+
+			/**
+			 * An empty description of listeners.
+			 */
+			public ListenerList() {
+				listener = new ArrayList<>();
+			}
+
+			/**
+			 * @param r
+			 *            The run whose listeners we're talking about.
+			 * @param ub
+			 *            Uri factory; must've been secured
+			 */
+			private ListenerList(TavernaRun r, UriBuilder ub) {
+				super(ub);
+				listener = new ArrayList<>(r.getListeners().size());
+				UriBuilder pathUB = ub.clone().path("{name}");
+				for (Listener l : r.getListeners())
+					listener.add(new Uri(pathUB.build(l.getName())));
+			}
+
+			/**
+			 * @param run
+			 *            The run whose listeners we're talking about.
+			 * @param ui
+			 *            The source of information about URIs.
+			 * @param path
+			 *            Where we are relative to the URI source.
+			 * @param parts
+			 *            Anything required to fill out the path.
+			 */
+			ListenerList(TavernaRun run, UriInfo ui, String path,
+					String... parts) {
+				this(run, secure(fromUri(new Uri(ui, path, parts).ref)));
+			}
+		}
+
+		/**
+		 * An empty description of a run.
+		 */
+		public RunDescription() {
+		}
+
+		/**
+		 * A description of a particular run.
+		 * 
+		 * @param run
+		 *            The run to describe.
+		 * @param ui
+		 *            The factory for URIs.
+		 */
+		public RunDescription(TavernaRun run, UriInfo ui) {
+			super(true);
+			creationWorkflow = new Uri(ui, WF);
+			expiry = new Expiry(run, ui, T_EXPIRE);
+			status = new Uri(ui, STATUS);
+			workingDirectory = new Uri(ui, DIR);
+			listeners = new ListenerList(run, ui, LISTEN);
+			securityContext = new Uri(ui, SEC);
+			inputs = new Uri(ui, IN);
+			output = new Uri(ui, OUT);
+			createTime = new Uri(ui, T_CREATE);
+			startTime = new Uri(ui, T_START);
+			finishTime = new Uri(ui, T_FINISH);
+			interaction = new Uri(ui, FEED_URL_DIR);
+			name = new Uri(ui, NAME);
+			owner = run.getSecurityContext().getOwner().getName();
+			stdout = new Uri(ui, STDOUT);
+			stderr = new Uri(ui, STDERR);
+			usage = new Uri(ui, USAGE);
+			log = new Uri(ui, LOG);
+			runBundle = new Uri(ui, RUNBUNDLE);
+			generateProvenance = new Uri(ui, GENERATE_PROVENANCE);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerSecurityREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerSecurityREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerSecurityREST.java
new file mode 100644
index 0000000..f5101e7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerSecurityREST.java
@@ -0,0 +1,788 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static java.util.Collections.emptyList;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.rest.ContentTypes.JSON;
+import static org.taverna.server.master.rest.ContentTypes.TEXT;
+import static org.taverna.server.master.rest.ContentTypes.XML;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.CREDS;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_CRED;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_PERM;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_TRUST;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.OWNER;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.PERMS;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ROOT;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.TRUSTS;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Permission;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.common.Uri;
+import org.taverna.server.master.common.VersionedElement;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoCredentialException;
+
+/**
+ * Manages the security of the workflow run. In general, only the owner of a run
+ * may access this resource. Many of these security-related resources may only
+ * be changed before the run is set to operating.
+ * 
+ * @author Donal Fellows
+ */
+@RolesAllowed(USER)
+@Description("Manages the security of the workflow run. In general, only the "
+		+ "owner of a run may access this resource.")
+public interface TavernaServerSecurityREST {
+	interface PathNames {
+		final String ROOT = "/";
+		final String OWNER = "owner";
+		final String CREDS = "credentials";
+		final String ONE_CRED = CREDS + "/{id}";
+		final String TRUSTS = "trusts";
+		final String ONE_TRUST = TRUSTS + "/{id}";
+		final String PERMS = "permissions";
+		final String ONE_PERM = PERMS + "/{id}";
+	}
+
+	/**
+	 * Gets a description of the security information supported by the workflow
+	 * run.
+	 * 
+	 * @param ui
+	 *            About the URI used to access this resource.
+	 * @return A description of the security information.
+	 */
+	@GET
+	@Path(ROOT)
+	@Produces({ XML, JSON })
+	@Description("Gives a description of the security information supported "
+			+ "by the workflow run.")
+	@Nonnull
+	Descriptor describe(@Nonnull @Context UriInfo ui);
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ROOT)
+	@Description("Produces the description of the run security.")
+	Response descriptionOptions();
+
+	/**
+	 * Gets the identity of who owns the workflow run.
+	 * 
+	 * @return The name of the owner of the run.
+	 */
+	@GET
+	@Path(OWNER)
+	@Produces(TEXT)
+	@Description("Gives the identity of who owns the workflow run.")
+	@Nonnull
+	String getOwner();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(OWNER)
+	@Description("Produces the description of the run owner.")
+	Response ownerOptions();
+
+	/*
+	 * @PUT @Path("/") @Consumes(ContentTypes.BYTES) @CallCounted @Nonnull
+	 * public void set(@Nonnull InputStream contents, @Nonnull @Context UriInfo
+	 * ui);
+	 */
+
+	/**
+	 * @return A list of credentials supplied to this workflow run.
+	 */
+	@GET
+	@Path(CREDS)
+	@Produces({ XML, JSON })
+	@Description("Gives a list of credentials supplied to this workflow run.")
+	@Nonnull
+	CredentialList listCredentials();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(CREDS)
+	@Description("Produces the description of the run credentials' operations.")
+	Response credentialsOptions();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ONE_CRED)
+	@Description("Produces the description of one run credential's operations.")
+	Response credentialOptions(@PathParam("id") String id);
+
+	/**
+	 * Describe a particular credential.
+	 * 
+	 * @param id
+	 *            The id of the credential to fetch.
+	 * @return The description of the credential.
+	 * @throws NoCredentialException
+	 *             If the credential doesn't exist.
+	 */
+	@GET
+	@Path(ONE_CRED)
+	@Produces({ XML, JSON })
+	@Description("Describes a particular credential.")
+	@Nonnull
+	CredentialHolder getParticularCredential(@Nonnull @PathParam("id") String id)
+			throws NoCredentialException;
+
+	/**
+	 * Update a particular credential.
+	 * 
+	 * @param id
+	 *            The id of the credential to update.
+	 * @param c
+	 *            The details of the credential to use in the update.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return Description of the updated credential.
+	 * @throws InvalidCredentialException
+	 *             If the credential description isn't valid.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@PUT
+	@Path(ONE_CRED)
+	@Consumes({ XML, JSON })
+	@Produces({ XML, JSON })
+	@Description("Updates a particular credential.")
+	@Nonnull
+	CredentialHolder setParticularCredential(
+			@Nonnull @PathParam("id") String id, @Nonnull CredentialHolder c,
+			@Nonnull @Context UriInfo ui) throws InvalidCredentialException,
+			BadStateChangeException;
+
+	/**
+	 * Adds a new credential.
+	 * 
+	 * @param c
+	 *            The details of the credential to create.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return Description of the created credential.
+	 * @throws InvalidCredentialException
+	 *             If the credential description isn't valid.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@POST
+	@Path(CREDS)
+	@Consumes({ XML, JSON })
+	@Description("Creates a new credential.")
+	@Nonnull
+	Response addCredential(@Nonnull CredentialHolder c,
+			@Nonnull @Context UriInfo ui) throws InvalidCredentialException,
+			BadStateChangeException;
+
+	/**
+	 * Deletes all credentials associated with a run.
+	 * 
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return A characterisation of a successful delete.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@DELETE
+	@Path(CREDS)
+	@Description("Deletes all credentials.")
+	@Nonnull
+	Response deleteAllCredentials(@Nonnull @Context UriInfo ui)
+			throws BadStateChangeException;
+
+	/**
+	 * Deletes one credential associated with a run.
+	 * 
+	 * @param id
+	 *            The identity of the credential to delete.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return A characterisation of a successful delete.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@DELETE
+	@Path(ONE_CRED)
+	@Description("Deletes a particular credential.")
+	@Nonnull
+	Response deleteCredential(@Nonnull @PathParam("id") String id,
+			@Nonnull @Context UriInfo ui) throws BadStateChangeException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(TRUSTS)
+	@Description("Produces the description of the run trusted certificates' "
+			+ "operations.")
+	Response trustsOptions();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ONE_TRUST)
+	@Description("Produces the description of one run trusted certificate's "
+			+ "operations.")
+	Response trustOptions(@PathParam("id") String id);
+
+	/**
+	 * @return A list of trusted identities supplied to this workflow run.
+	 */
+	@GET
+	@Path(TRUSTS)
+	@Produces({ XML, JSON })
+	@Description("Gives a list of trusted identities supplied to this "
+			+ "workflow run.")
+	@Nonnull
+	TrustList listTrusted();
+
+	/**
+	 * Describe a particular trusted identity.
+	 * 
+	 * @param id
+	 *            The id of the trusted identity to fetch.
+	 * @return The description of the trusted identity.
+	 * @throws NoCredentialException
+	 *             If the trusted identity doesn't exist.
+	 */
+	@GET
+	@Path(ONE_TRUST)
+	@Produces({ XML, JSON })
+	@Description("Describes a particular trusted identity.")
+	@Nonnull
+	Trust getParticularTrust(@Nonnull @PathParam("id") String id)
+			throws NoCredentialException;
+
+	/**
+	 * Update a particular trusted identity.
+	 * 
+	 * @param id
+	 *            The id of the trusted identity to update.
+	 * @param t
+	 *            The details of the trusted identity to use in the update.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return Description of the updated trusted identity.
+	 * @throws InvalidCredentialException
+	 *             If the trusted identity description isn't valid.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@PUT
+	@Path(ONE_TRUST)
+	@Consumes({ XML, JSON })
+	@Produces({ XML, JSON })
+	@Description("Updates a particular trusted identity.")
+	@Nonnull
+	Trust setParticularTrust(@Nonnull @PathParam("id") String id,
+			@Nonnull Trust t, @Nonnull @Context UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException;
+
+	/**
+	 * Adds a new trusted identity.
+	 * 
+	 * @param t
+	 *            The details of the trusted identity to create.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return Description of the created trusted identity.
+	 * @throws InvalidCredentialException
+	 *             If the trusted identity description isn't valid.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@POST
+	@Path(TRUSTS)
+	@Consumes({ XML, JSON })
+	@Description("Adds a new trusted identity.")
+	@Nonnull
+	Response addTrust(@Nonnull Trust t, @Nonnull @Context UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException;
+
+	/**
+	 * Deletes all trusted identities associated with a run.
+	 * 
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return A characterisation of a successful delete.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@DELETE
+	@Path(TRUSTS)
+	@Description("Deletes all trusted identities.")
+	@Nonnull
+	Response deleteAllTrusts(@Nonnull @Context UriInfo ui)
+			throws BadStateChangeException;
+
+	/**
+	 * Deletes one trusted identity associated with a run.
+	 * 
+	 * @param id
+	 *            The identity of the trusted identity to delete.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return A characterisation of a successful delete.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@DELETE
+	@Path(ONE_TRUST)
+	@Description("Deletes a particular trusted identity.")
+	@Nonnull
+	Response deleteTrust(@Nonnull @PathParam("id") String id,
+			@Nonnull @Context UriInfo ui) throws BadStateChangeException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(PERMS)
+	@Description("Produces the description of the run permissions' operations.")
+	Response permissionsOptions();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ONE_PERM)
+	@Description("Produces the description of one run permission's operations.")
+	Response permissionOptions(@PathParam("id") String id);
+
+	/**
+	 * @return A list of (non-default) permissions associated with this workflow
+	 *         run.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 */
+	@GET
+	@Path(PERMS)
+	@Produces({ XML, JSON })
+	@Description("Gives a list of all non-default permissions associated with "
+			+ "the enclosing workflow run. By default, nobody has any access "
+			+ "at all except for the owner of the run.")
+	@Nonnull
+	PermissionsDescription describePermissions(@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Describe the particular permission granted to a user.
+	 * 
+	 * @param id
+	 *            The name of the user whose permissions are to be described.
+	 * @return The permission they are granted.
+	 */
+	@GET
+	@Path(ONE_PERM)
+	@Produces(TEXT)
+	@Description("Describes the permission granted to a particular user.")
+	@Nonnull
+	Permission describePermission(@Nonnull @PathParam("id") String id);
+
+	/**
+	 * Update the permission granted to a user.
+	 * 
+	 * @param id
+	 *            The name of the user whose permissions are to be updated. Note
+	 *            that the owner always has full permissions.
+	 * @param perm
+	 *            The permission level to set.
+	 * @return The permission level that has actually been set.
+	 */
+	@PUT
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Path(ONE_PERM)
+	@Description("Updates the permissions granted to a particular user.")
+	@Nonnull
+	Permission setPermission(@Nonnull @PathParam("id") String id,
+			@Nonnull Permission perm);
+
+	/**
+	 * Delete the permissions associated with a user, which restores them to the
+	 * default (no access unless they are the owner or have admin privileges).
+	 * 
+	 * @param id
+	 *            The name of the user whose permissions are to be revoked.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return An indication that the delete has been successful (or not).
+	 */
+	@DELETE
+	@Path(ONE_PERM)
+	@Description("Deletes (by resetting to default) the permissions "
+			+ "associated with a particular user.")
+	@Nonnull
+	Response deletePermission(@Nonnull @PathParam("id") String id,
+			@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Manufacture a permission setting for a previously-unknown user.
+	 * 
+	 * @param desc
+	 *            A description of the name of the user and the permission level
+	 *            to grant them.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return An indication that the create has been successful (or not).
+	 */
+	@POST
+	@Path(PERMS)
+	@Consumes({ XML, JSON })
+	@Description("Creates a new assignment of permissions to a particular user.")
+	@Nonnull
+	Response makePermission(@Nonnull PermissionDescription desc,
+			@Nonnull @Context UriInfo ui);
+
+	/**
+	 * A description of the security resources associated with a workflow run.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "securityDescriptor")
+	@XmlType(name = "SecurityDescriptor")
+	public static final class Descriptor extends VersionedElement {
+		/** The identity of the owner of the enclosing workflow run. */
+		@XmlElement
+		public String owner;
+		/** Where to get the permissions on the run. */
+		@XmlElement
+		public Uri permissions;
+
+		/** Characterisation of the credentials attached to the run. */
+		@XmlElement
+		public Credentials credentials;
+		/** Characterisation of the trusted certificates attached to the run. */
+		@XmlElement
+		public Trusts trusts;
+
+		public Descriptor() {
+		}
+
+		/**
+		 * Initialise a description of the security context.
+		 * 
+		 * @param ub
+		 *            How to build URIs.
+		 * @param owner
+		 *            Who owns the context.
+		 * @param credential
+		 *            The credentials associated with the context.
+		 * @param trust
+		 *            The trusted certificates associated with the context.
+		 */
+		public Descriptor(@Nonnull UriBuilder ub, @Nonnull String owner,
+				@Nonnull Credential[] credential, @Nonnull Trust[] trust) {
+			super(true);
+			this.owner = owner;
+			this.permissions = new Uri(ub, PERMS);
+			this.credentials = new Credentials(new Uri(ub, CREDS).ref,
+					credential);
+			this.trusts = new Trusts(new Uri(ub, TRUSTS).ref, trust);
+		}
+
+		/**
+		 * A description of credentials associated with a workflow run.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "CredentialCollection")
+		public static final class Credentials {
+			/** Reference to the collection of credentials */
+			@XmlAttribute(name = "href", namespace = XLINK)
+			@XmlSchemaType(name = "anyURI")
+			public URI href;
+			/** Descriptions of the credentials themselves. */
+			@XmlElement
+			public List<CredentialHolder> credential = new ArrayList<>();
+
+			public Credentials() {
+			}
+
+			/**
+			 * Initialise a description of the credentials.
+			 * 
+			 * @param uri
+			 *            the URI of the collection.
+			 * @param credential
+			 *            The credentials in the collection.
+			 */
+			public Credentials(@Nonnull URI uri,
+					@Nonnull Credential[] credential) {
+				this.href = uri;
+				for (Credential c : credential)
+					this.credential.add(new CredentialHolder(c));
+			}
+		}
+
+		/**
+		 * A description of trusted certificates associated with a workflow run.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "TrustCollection")
+		public static final class Trusts {
+			/** Reference to the collection of trusted certs */
+			@XmlAttribute(name = "href", namespace = XLINK)
+			@XmlSchemaType(name = "anyURI")
+			public URI href;
+			/** Descriptions of the trusted certs themselves. */
+			@XmlElement
+			public Trust[] trust;
+
+			public Trusts() {
+			}
+
+			/**
+			 * Initialise a description of the trusted certificates.
+			 * 
+			 * @param uri
+			 *            the URI of the collection.
+			 * @param trust
+			 *            The trusted certificates in the collection.
+			 */
+			public Trusts(@Nonnull URI uri, @Nonnull Trust[] trust) {
+				this.href = uri;
+				this.trust = trust.clone();
+			}
+		}
+	}
+
+	/**
+	 * A container for a credential, used to work around issues with type
+	 * inference in CXF's REST service handling and JAXB.
+	 * 
+	 * @see Credential.KeyPair
+	 * @see Credential.Password
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "credential")
+	@XmlType(name = "Credential")
+	public static final class CredentialHolder {
+		/**
+		 * The credential inside this holder.
+		 */
+		@XmlElements({
+				@XmlElement(name = "keypair", namespace = SERVER, type = Credential.KeyPair.class, required = true),
+				@XmlElement(name = "userpass", namespace = SERVER, type = Credential.Password.class, required = true) })
+		public Credential credential;
+
+		public CredentialHolder() {
+		}
+
+		public CredentialHolder(Credential credential) {
+			this.credential = credential;
+		}
+
+		/**
+		 * Convenience accessor function.
+		 * 
+		 * @return The keypair credential held in this holder.
+		 */
+		@XmlTransient
+		public Credential.KeyPair getKeypair() {
+			return (Credential.KeyPair) this.credential;
+		}
+
+		/**
+		 * Convenience accessor function.
+		 * 
+		 * @return The userpass credential held in this holder.
+		 */
+		@XmlTransient
+		public Credential.Password getUserpass() {
+			return (Credential.Password) this.credential;
+		}
+	}
+
+	/**
+	 * A simple list of credential descriptions.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "credentials")
+	public static final class CredentialList extends VersionedElement {
+		/** The descriptions of the credentials */
+		@XmlElement
+		@Nonnull
+		public List<CredentialHolder> credential = new ArrayList<>();
+
+		public CredentialList() {
+		}
+
+		/**
+		 * Initialise the list of credentials.
+		 * 
+		 * @param credential
+		 *            The descriptions of individual credentials.
+		 */
+		public CredentialList(@Nonnull Credential[] credential) {
+			super(true);
+			for (Credential c : credential)
+				this.credential.add(new CredentialHolder(c));
+		}
+	}
+
+	/**
+	 * A simple list of trusted certificate descriptions.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "trustedIdentities")
+	public static final class TrustList extends VersionedElement {
+		/** The descriptions of the trusted certificates */
+		@XmlElement
+		public Trust[] trust;
+
+		public TrustList() {
+		}
+
+		/**
+		 * Initialise the list of trusted certificates.
+		 * 
+		 * @param trust
+		 *            The descriptions of individual certificates.
+		 */
+		public TrustList(@Nonnull Trust[] trust) {
+			super(true);
+			this.trust = trust.clone();
+		}
+	}
+
+	/**
+	 * A description of the permissions granted to others by the owner of a
+	 * workflow run.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "permissionsDescriptor")
+	public static class PermissionsDescription extends VersionedElement {
+		/**
+		 * A description of the permissions granted to one user by the owner of
+		 * a workflow run.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlRootElement(name = "userPermission")
+		public static class LinkedPermissionDescription extends Uri {
+			/** Who is this granted to? */
+			@XmlElement
+			public String userName;
+			/** What are they granted? */
+			@XmlElement
+			public Permission permission;
+
+			public LinkedPermissionDescription() {
+			}
+
+			/**
+			 * Initialise a description of one user's permissions.
+			 * 
+			 * @param ub
+			 *            How to build the URI to this permission. Already
+			 *            secured.
+			 * @param userName
+			 *            Who this relates to.
+			 * @param permission
+			 *            What permission is granted.
+			 * @param strings
+			 *            Parameters to the URI builder.
+			 */
+			LinkedPermissionDescription(@Nonnull UriBuilder ub,
+					@Nonnull String userName, @Nonnull Permission permission,
+					String... strings) {
+				super(ub, strings);
+				this.userName = userName;
+				this.permission = permission;
+			}
+		}
+
+		/** List of descriptions of permissions. */
+		@XmlElement
+		public List<LinkedPermissionDescription> permission;
+
+		public PermissionsDescription() {
+			permission = emptyList();
+		}
+
+		/**
+		 * Initialise the description of a collection of permissions.
+		 * 
+		 * @param ub
+		 *            How to build URIs to this collection. Must have already
+		 *            been secured.
+		 * @param permissionMap
+		 *            The permissions to describe.
+		 */
+		public PermissionsDescription(@Nonnull UriBuilder ub,
+				@Nonnull Map<String, Permission> permissionMap) {
+			permission = new ArrayList<>();
+			List<String> userNames = new ArrayList<>(permissionMap.keySet());
+			Collections.sort(userNames);
+			for (String user : userNames)
+				permission.add(new LinkedPermissionDescription(ub, user,
+						permissionMap.get(user), user));
+		}
+	}
+
+	/**
+	 * An instruction to update the permissions for a user.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "permissionUpdate")
+	public static class PermissionDescription {
+		/** Who to set the permission for? */
+		@XmlElement
+		public String userName;
+		/** What permission to grant them? */
+		@XmlElement
+		public Permission permission;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/AccessDeniedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/AccessDeniedHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/AccessDeniedHandler.java
new file mode 100644
index 0000000..3418975
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/AccessDeniedHandler.java
@@ -0,0 +1,34 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.springframework.security.access.AccessDeniedException;
+
+public class AccessDeniedHandler extends HandlerCore implements
+		ExceptionMapper<AccessDeniedException> {
+	@Override
+	public Response toResponse(AccessDeniedException exception) {
+		return respond(FORBIDDEN, exception);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadInputPortNameHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadInputPortNameHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadInputPortNameHandler.java
new file mode 100644
index 0000000..a78693d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadInputPortNameHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.BadInputPortNameException;
+
+@Provider
+public class BadInputPortNameHandler extends HandlerCore implements
+		ExceptionMapper<BadInputPortNameException> {
+	@Override
+	public Response toResponse(BadInputPortNameException exn) {
+		return respond(NOT_FOUND, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadPropertyValueHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadPropertyValueHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadPropertyValueHandler.java
new file mode 100644
index 0000000..e956749
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadPropertyValueHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+
+@Provider
+public class BadPropertyValueHandler extends HandlerCore implements
+		ExceptionMapper<BadPropertyValueException> {
+	@Override
+	public Response toResponse(BadPropertyValueException exn) {
+		return respond(BAD_REQUEST, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadStateChangeHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadStateChangeHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadStateChangeHandler.java
new file mode 100644
index 0000000..53f441b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadStateChangeHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.BadStateChangeException;
+
+@Provider
+public class BadStateChangeHandler extends HandlerCore implements
+		ExceptionMapper<BadStateChangeException> {
+	@Override
+	public Response toResponse(BadStateChangeException exn) {
+		return respond(BAD_REQUEST, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/EntryHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/EntryHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/EntryHandler.java
new file mode 100644
index 0000000..bc79c22
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/EntryHandler.java
@@ -0,0 +1,147 @@
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonMap;
+import static javax.ws.rs.core.Response.notAcceptable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Variant;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.writer.Writer;
+import org.springframework.beans.factory.annotation.Required;
+
+@Provider
+@Produces({ "application/atom+xml", "application/atom+xml;type=entry" })
+@Consumes({ "application/atom+xml", "application/atom+xml;type=entry" })
+public class EntryHandler implements MessageBodyWriter<Entry>,
+		MessageBodyReader<Entry> {
+	private static final String ENC = "UTF-8";
+	private static final MediaType ENTRY = new MediaType("application",
+			"atom+xml", singletonMap("type", "entry"));
+	private static final Variant VARIANT = new Variant(ENTRY, (String) null,
+			ENC);
+	private static final Charset UTF8 = Charset.forName(ENC);
+
+	@Required
+	public void setAbdera(Abdera abdera) {
+		parser = abdera.getParser();
+		writer = abdera.getWriterFactory().getWriter("prettyxml");
+	}
+
+	private Parser parser;
+	private Writer writer;
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (!Entry.class.isAssignableFrom(type))
+			return false;
+		if (!ENTRY.isCompatible(mediaType))
+			return false;
+		if (mediaType.getParameters().containsKey("type"))
+			return "entry".equalsIgnoreCase(mediaType.getParameters().get(
+					"type"));
+		return true;
+	}
+
+	@Override
+	public Entry readFrom(Class<Entry> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		Charset cs = UTF8;
+		try {
+			String charset = mediaType.getParameters().get("charset");
+			if (charset != null)
+				cs = Charset.forName(charset);
+		} catch (IllegalCharsetNameException e) {
+			throw new WebApplicationException(notAcceptable(asList(VARIANT))
+					.entity("bad charset name").build());
+		} catch (UnsupportedCharsetException e) {
+			throw new WebApplicationException(notAcceptable(asList(VARIANT))
+					.entity("unsupportd charset name").build());
+		}
+		try {
+			Document<Entry> doc = parser.parse(new InputStreamReader(
+					entityStream, cs));
+			if (!Entry.class.isAssignableFrom(doc.getRoot().getClass())) {
+				throw new WebApplicationException(
+						notAcceptable(asList(VARIANT)).entity(
+								"not really a feed entry").build());
+			}
+			return doc.getRoot();
+		} catch (ClassCastException e) {
+			throw new WebApplicationException(notAcceptable(asList(VARIANT))
+					.entity("not really a feed entry").build());
+
+		}
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (!Entry.class.isAssignableFrom(type))
+			return false;
+		if (!ENTRY.isCompatible(mediaType))
+			return false;
+		if (mediaType.getParameters().containsKey("type"))
+			return "entry".equalsIgnoreCase(mediaType.getParameters().get(
+					"type"));
+		return true;
+	}
+
+	@Override
+	public long getSize(Entry t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(Entry t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		httpHeaders.putSingle("Content-Type", ENTRY.toString() + ";charset="
+				+ ENC);
+		writer.writeTo(t, new OutputStreamWriter(entityStream, UTF8));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FeedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FeedHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FeedHandler.java
new file mode 100644
index 0000000..77e7e49
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FeedHandler.java
@@ -0,0 +1,82 @@
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static java.util.Collections.singletonMap;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.writer.Writer;
+import org.springframework.beans.factory.annotation.Required;
+
+@Provider
+@Produces({ "application/atom+xml", "application/atom+xml;type=feed" })
+public class FeedHandler implements MessageBodyWriter<Feed> {
+	private static final MediaType FEED = new MediaType("application",
+			"atom+xml", singletonMap("type", "feed"));
+	private static final String ENC = "UTF-8";
+
+	@Required
+	public void setAbdera(Abdera abdera) {
+		writer = abdera.getWriterFactory().getWriter("prettyxml");
+	}
+
+	private Writer writer;
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (!Feed.class.isAssignableFrom(type))
+			return false;
+		if (!FEED.isCompatible(mediaType))
+			return false;
+		if (mediaType.getParameters().containsKey("type"))
+			return "feed".equalsIgnoreCase(mediaType.getParameters()
+					.get("type"));
+		return true;
+	}
+
+	@Override
+	public long getSize(Feed t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(Feed t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		httpHeaders.putSingle("Content-Type", FEED.toString() + ";charset="
+				+ ENC);
+		writer.writeTo(t, new OutputStreamWriter(entityStream, ENC));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileConcatenationHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileConcatenationHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileConcatenationHandler.java
new file mode 100644
index 0000000..e0924ad
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileConcatenationHandler.java
@@ -0,0 +1,77 @@
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.FileConcatenation;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+public class FileConcatenationHandler implements
+		MessageBodyWriter<FileConcatenation> {
+	/** How much to pull from the worker in one read. */
+	private int maxChunkSize;
+
+	/**
+	 * @param maxChunkSize
+	 *            How much to pull from the worker in one read.
+	 */
+	@Required
+	public void setMaxChunkSize(int maxChunkSize) {
+		this.maxChunkSize = maxChunkSize;
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return type.isAssignableFrom(FileConcatenation.class);
+	}
+
+	@Override
+	public long getSize(FileConcatenation fc, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return fc.size();
+	}
+
+	@Override
+	public void writeTo(FileConcatenation fc, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException {
+		for (File f : fc)
+			try {
+				byte[] buffer;
+				for (int off = 0; true ; off += buffer.length) {
+					buffer = f.getContents(off, maxChunkSize);
+					if (buffer == null || buffer.length == 0)
+						break;
+					entityStream.write(buffer);
+				}
+			} catch (FilesystemAccessException e) {
+				// Ignore/skip to next file
+			}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileMessageHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileMessageHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileMessageHandler.java
new file mode 100644
index 0000000..7d2b381
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileMessageHandler.java
@@ -0,0 +1,93 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.commons.logging.Log;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * How to write out a File object with JAX-RS.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+public class FileMessageHandler implements MessageBodyWriter<File> {
+	private Log log = getLog("Taverna.Server.Webapp");
+	/** How much to pull from the worker in one read. */
+	private int maxChunkSize;
+
+	/**
+	 * @param maxChunkSize
+	 *            How much to pull from the worker in one read.
+	 */
+	public void setMaxChunkSize(int maxChunkSize) {
+		this.maxChunkSize = maxChunkSize;
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return File.class.isAssignableFrom(type);
+	}
+
+	@Override
+	public long getSize(File t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		try {
+			return t.getSize(); // Is it really raw bytes?
+		} catch (FilesystemAccessException e) {
+			log.info("failed to get file length", e);
+			return -1;
+		}
+	}
+
+	@Override
+	public void writeTo(File t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		try {
+			int off = 0;
+			while (true) {
+				byte[] buffer = t.getContents(off, maxChunkSize);
+				if (buffer == null || buffer.length == 0)
+					break;
+				entityStream.write(buffer);
+				off += buffer.length;
+			}
+		} catch (FilesystemAccessException e) {
+			throw new IOException("problem when reading file", e);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileSegmentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileSegmentHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileSegmentHandler.java
new file mode 100644
index 0000000..82d5e0a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileSegmentHandler.java
@@ -0,0 +1,87 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static java.lang.Math.min;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.rest.FileSegment;
+
+/**
+ * How to write out a segment of a file with JAX-RS.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+public class FileSegmentHandler implements MessageBodyWriter<FileSegment> {
+	/** How much to pull from the worker in one read. */
+	private int maxChunkSize;
+
+	/**
+	 * @param maxChunkSize
+	 *            How much to pull from the worker in one read.
+	 */
+	public void setMaxChunkSize(int maxChunkSize) {
+		this.maxChunkSize = maxChunkSize;
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return FileSegment.class.isAssignableFrom(type);
+	}
+
+	@Override
+	public long getSize(FileSegment t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return t.to - t.from;
+	}
+
+	@Override
+	public void writeTo(FileSegment t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		try {
+			int off = t.from;
+			while (off < t.to) {
+				byte[] buffer = t.file.getContents(off,
+						min(maxChunkSize, t.to - off));
+				if (buffer == null || buffer.length == 0)
+					break;
+				entityStream.write(buffer);
+				off += buffer.length;
+			}
+		} catch (FilesystemAccessException e) {
+			throw new IOException("problem when reading file", e);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FilesystemAccessHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FilesystemAccessHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FilesystemAccessHandler.java
new file mode 100644
index 0000000..cfa863c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FilesystemAccessHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+@Provider
+public class FilesystemAccessHandler extends HandlerCore implements
+		ExceptionMapper<FilesystemAccessException> {
+	@Override
+	public Response toResponse(FilesystemAccessException exn) {
+		return respond(FORBIDDEN, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/GeneralFailureHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/GeneralFailureHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/GeneralFailureHandler.java
new file mode 100644
index 0000000..fe4ba0b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/GeneralFailureHandler.java
@@ -0,0 +1,34 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.taverna.server.master.exceptions.GeneralFailureException;
+
+public class GeneralFailureHandler extends HandlerCore implements
+		ExceptionMapper<GeneralFailureException> {
+	@Override
+	public Response toResponse(GeneralFailureException exception) {
+		return respond(INTERNAL_SERVER_ERROR, exception);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/HandlerCore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/HandlerCore.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/HandlerCore.java
new file mode 100644
index 0000000..bc92154
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/HandlerCore.java
@@ -0,0 +1,84 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
+import static javax.ws.rs.core.Response.status;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.commons.logging.Log;
+import org.taverna.server.master.api.ManagementModel;
+
+/**
+ * Base class for handlers that grants Spring-enabled access to the management
+ * model.
+ * 
+ * @author Donal Fellows
+ */
+public class HandlerCore {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private ManagementModel managementModel;
+
+	/**
+	 * @param managementModel
+	 *            the managementModel to set
+	 */
+	public void setManagementModel(ManagementModel managementModel) {
+		this.managementModel = managementModel;
+	}
+
+	/**
+	 * Simplified interface for building responses.
+	 * 
+	 * @param status
+	 *            What status code to use?
+	 * @param exception
+	 *            What exception to report on?
+	 * @return The build response.
+	 */
+	protected Response respond(Response.Status status, Exception exception) {
+		if (managementModel.getLogOutgoingExceptions()
+				|| status.getStatusCode() >= 500)
+			log.info("converting exception to response", exception);
+		return status(status).type(TEXT_PLAIN_TYPE)
+				.entity(exception.getMessage()).build();
+	}
+
+	/**
+	 * Simplified interface for building responses.
+	 * 
+	 * @param status
+	 *            What status code to use?
+	 * @param partialMessage
+	 *            The prefix to the message.
+	 * @param exception
+	 *            What exception to report on?
+	 * @return The build response.
+	 */
+	protected Response respond(Response.Status status, String partialMessage,
+			Exception exception) {
+		if (managementModel.getLogOutgoingExceptions()
+				|| status.getStatusCode() >= 500)
+			log.info("converting exception to response", exception);
+		return status(status).type(TEXT_PLAIN_TYPE)
+				.entity(partialMessage + "\n" + exception.getMessage()).build();
+	}
+}



[10/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java
deleted file mode 100644
index a78693d..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.BadInputPortNameException;
-
-@Provider
-public class BadInputPortNameHandler extends HandlerCore implements
-		ExceptionMapper<BadInputPortNameException> {
-	@Override
-	public Response toResponse(BadInputPortNameException exn) {
-		return respond(NOT_FOUND, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java
deleted file mode 100644
index e956749..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-
-@Provider
-public class BadPropertyValueHandler extends HandlerCore implements
-		ExceptionMapper<BadPropertyValueException> {
-	@Override
-	public Response toResponse(BadPropertyValueException exn) {
-		return respond(BAD_REQUEST, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java
deleted file mode 100644
index 53f441b..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.BadStateChangeException;
-
-@Provider
-public class BadStateChangeHandler extends HandlerCore implements
-		ExceptionMapper<BadStateChangeException> {
-	@Override
-	public Response toResponse(BadStateChangeException exn) {
-		return respond(BAD_REQUEST, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java
deleted file mode 100644
index bc79c22..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonMap;
-import static javax.ws.rs.core.Response.notAcceptable;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.nio.charset.Charset;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Variant;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.model.Document;
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.parser.Parser;
-import org.apache.abdera.writer.Writer;
-import org.springframework.beans.factory.annotation.Required;
-
-@Provider
-@Produces({ "application/atom+xml", "application/atom+xml;type=entry" })
-@Consumes({ "application/atom+xml", "application/atom+xml;type=entry" })
-public class EntryHandler implements MessageBodyWriter<Entry>,
-		MessageBodyReader<Entry> {
-	private static final String ENC = "UTF-8";
-	private static final MediaType ENTRY = new MediaType("application",
-			"atom+xml", singletonMap("type", "entry"));
-	private static final Variant VARIANT = new Variant(ENTRY, (String) null,
-			ENC);
-	private static final Charset UTF8 = Charset.forName(ENC);
-
-	@Required
-	public void setAbdera(Abdera abdera) {
-		parser = abdera.getParser();
-		writer = abdera.getWriterFactory().getWriter("prettyxml");
-	}
-
-	private Parser parser;
-	private Writer writer;
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (!Entry.class.isAssignableFrom(type))
-			return false;
-		if (!ENTRY.isCompatible(mediaType))
-			return false;
-		if (mediaType.getParameters().containsKey("type"))
-			return "entry".equalsIgnoreCase(mediaType.getParameters().get(
-					"type"));
-		return true;
-	}
-
-	@Override
-	public Entry readFrom(Class<Entry> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		Charset cs = UTF8;
-		try {
-			String charset = mediaType.getParameters().get("charset");
-			if (charset != null)
-				cs = Charset.forName(charset);
-		} catch (IllegalCharsetNameException e) {
-			throw new WebApplicationException(notAcceptable(asList(VARIANT))
-					.entity("bad charset name").build());
-		} catch (UnsupportedCharsetException e) {
-			throw new WebApplicationException(notAcceptable(asList(VARIANT))
-					.entity("unsupportd charset name").build());
-		}
-		try {
-			Document<Entry> doc = parser.parse(new InputStreamReader(
-					entityStream, cs));
-			if (!Entry.class.isAssignableFrom(doc.getRoot().getClass())) {
-				throw new WebApplicationException(
-						notAcceptable(asList(VARIANT)).entity(
-								"not really a feed entry").build());
-			}
-			return doc.getRoot();
-		} catch (ClassCastException e) {
-			throw new WebApplicationException(notAcceptable(asList(VARIANT))
-					.entity("not really a feed entry").build());
-
-		}
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (!Entry.class.isAssignableFrom(type))
-			return false;
-		if (!ENTRY.isCompatible(mediaType))
-			return false;
-		if (mediaType.getParameters().containsKey("type"))
-			return "entry".equalsIgnoreCase(mediaType.getParameters().get(
-					"type"));
-		return true;
-	}
-
-	@Override
-	public long getSize(Entry t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(Entry t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		httpHeaders.putSingle("Content-Type", ENTRY.toString() + ";charset="
-				+ ENC);
-		writer.writeTo(t, new OutputStreamWriter(entityStream, UTF8));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java
deleted file mode 100644
index 77e7e49..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static java.util.Collections.singletonMap;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.model.Feed;
-import org.apache.abdera.writer.Writer;
-import org.springframework.beans.factory.annotation.Required;
-
-@Provider
-@Produces({ "application/atom+xml", "application/atom+xml;type=feed" })
-public class FeedHandler implements MessageBodyWriter<Feed> {
-	private static final MediaType FEED = new MediaType("application",
-			"atom+xml", singletonMap("type", "feed"));
-	private static final String ENC = "UTF-8";
-
-	@Required
-	public void setAbdera(Abdera abdera) {
-		writer = abdera.getWriterFactory().getWriter("prettyxml");
-	}
-
-	private Writer writer;
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (!Feed.class.isAssignableFrom(type))
-			return false;
-		if (!FEED.isCompatible(mediaType))
-			return false;
-		if (mediaType.getParameters().containsKey("type"))
-			return "feed".equalsIgnoreCase(mediaType.getParameters()
-					.get("type"));
-		return true;
-	}
-
-	@Override
-	public long getSize(Feed t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(Feed t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		httpHeaders.putSingle("Content-Type", FEED.toString() + ";charset="
-				+ ENC);
-		writer.writeTo(t, new OutputStreamWriter(entityStream, ENC));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java
deleted file mode 100644
index e0924ad..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.FileConcatenation;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-public class FileConcatenationHandler implements
-		MessageBodyWriter<FileConcatenation> {
-	/** How much to pull from the worker in one read. */
-	private int maxChunkSize;
-
-	/**
-	 * @param maxChunkSize
-	 *            How much to pull from the worker in one read.
-	 */
-	@Required
-	public void setMaxChunkSize(int maxChunkSize) {
-		this.maxChunkSize = maxChunkSize;
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return type.isAssignableFrom(FileConcatenation.class);
-	}
-
-	@Override
-	public long getSize(FileConcatenation fc, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return fc.size();
-	}
-
-	@Override
-	public void writeTo(FileConcatenation fc, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException {
-		for (File f : fc)
-			try {
-				byte[] buffer;
-				for (int off = 0; true ; off += buffer.length) {
-					buffer = f.getContents(off, maxChunkSize);
-					if (buffer == null || buffer.length == 0)
-						break;
-					entityStream.write(buffer);
-				}
-			} catch (FilesystemAccessException e) {
-				// Ignore/skip to next file
-			}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java
deleted file mode 100644
index 7d2b381..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.commons.logging.Log;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-/**
- * How to write out a File object with JAX-RS.
- * 
- * @author Donal Fellows
- */
-@Provider
-public class FileMessageHandler implements MessageBodyWriter<File> {
-	private Log log = getLog("Taverna.Server.Webapp");
-	/** How much to pull from the worker in one read. */
-	private int maxChunkSize;
-
-	/**
-	 * @param maxChunkSize
-	 *            How much to pull from the worker in one read.
-	 */
-	public void setMaxChunkSize(int maxChunkSize) {
-		this.maxChunkSize = maxChunkSize;
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return File.class.isAssignableFrom(type);
-	}
-
-	@Override
-	public long getSize(File t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		try {
-			return t.getSize(); // Is it really raw bytes?
-		} catch (FilesystemAccessException e) {
-			log.info("failed to get file length", e);
-			return -1;
-		}
-	}
-
-	@Override
-	public void writeTo(File t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		try {
-			int off = 0;
-			while (true) {
-				byte[] buffer = t.getContents(off, maxChunkSize);
-				if (buffer == null || buffer.length == 0)
-					break;
-				entityStream.write(buffer);
-				off += buffer.length;
-			}
-		} catch (FilesystemAccessException e) {
-			throw new IOException("problem when reading file", e);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java
deleted file mode 100644
index 82d5e0a..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static java.lang.Math.min;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.rest.FileSegment;
-
-/**
- * How to write out a segment of a file with JAX-RS.
- * 
- * @author Donal Fellows
- */
-@Provider
-public class FileSegmentHandler implements MessageBodyWriter<FileSegment> {
-	/** How much to pull from the worker in one read. */
-	private int maxChunkSize;
-
-	/**
-	 * @param maxChunkSize
-	 *            How much to pull from the worker in one read.
-	 */
-	public void setMaxChunkSize(int maxChunkSize) {
-		this.maxChunkSize = maxChunkSize;
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return FileSegment.class.isAssignableFrom(type);
-	}
-
-	@Override
-	public long getSize(FileSegment t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return t.to - t.from;
-	}
-
-	@Override
-	public void writeTo(FileSegment t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		try {
-			int off = t.from;
-			while (off < t.to) {
-				byte[] buffer = t.file.getContents(off,
-						min(maxChunkSize, t.to - off));
-				if (buffer == null || buffer.length == 0)
-					break;
-				entityStream.write(buffer);
-				off += buffer.length;
-			}
-		} catch (FilesystemAccessException e) {
-			throw new IOException("problem when reading file", e);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java
deleted file mode 100644
index cfa863c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-@Provider
-public class FilesystemAccessHandler extends HandlerCore implements
-		ExceptionMapper<FilesystemAccessException> {
-	@Override
-	public Response toResponse(FilesystemAccessException exn) {
-		return respond(FORBIDDEN, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java
deleted file mode 100644
index fe4ba0b..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.taverna.server.master.exceptions.GeneralFailureException;
-
-public class GeneralFailureHandler extends HandlerCore implements
-		ExceptionMapper<GeneralFailureException> {
-	@Override
-	public Response toResponse(GeneralFailureException exception) {
-		return respond(INTERNAL_SERVER_ERROR, exception);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java
deleted file mode 100644
index bc92154..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
-import static javax.ws.rs.core.Response.status;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import javax.ws.rs.core.Response;
-
-import org.apache.commons.logging.Log;
-import org.taverna.server.master.api.ManagementModel;
-
-/**
- * Base class for handlers that grants Spring-enabled access to the management
- * model.
- * 
- * @author Donal Fellows
- */
-public class HandlerCore {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private ManagementModel managementModel;
-
-	/**
-	 * @param managementModel
-	 *            the managementModel to set
-	 */
-	public void setManagementModel(ManagementModel managementModel) {
-		this.managementModel = managementModel;
-	}
-
-	/**
-	 * Simplified interface for building responses.
-	 * 
-	 * @param status
-	 *            What status code to use?
-	 * @param exception
-	 *            What exception to report on?
-	 * @return The build response.
-	 */
-	protected Response respond(Response.Status status, Exception exception) {
-		if (managementModel.getLogOutgoingExceptions()
-				|| status.getStatusCode() >= 500)
-			log.info("converting exception to response", exception);
-		return status(status).type(TEXT_PLAIN_TYPE)
-				.entity(exception.getMessage()).build();
-	}
-
-	/**
-	 * Simplified interface for building responses.
-	 * 
-	 * @param status
-	 *            What status code to use?
-	 * @param partialMessage
-	 *            The prefix to the message.
-	 * @param exception
-	 *            What exception to report on?
-	 * @return The build response.
-	 */
-	protected Response respond(Response.Status status, String partialMessage,
-			Exception exception) {
-		if (managementModel.getLogOutgoingExceptions()
-				|| status.getStatusCode() >= 500)
-			log.info("converting exception to response", exception);
-		return status(status).type(TEXT_PLAIN_TYPE)
-				.entity(partialMessage + "\n" + exception.getMessage()).build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java
deleted file mode 100644
index d7ec8f4..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.UNSUPPORTED_MEDIA_TYPE;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-@Provider
-public class IllegalArgumentHandler extends HandlerCore implements
-		ExceptionMapper<IllegalArgumentException> {
-	@Override
-	public Response toResponse(IllegalArgumentException exn) {
-		return respond(UNSUPPORTED_MEDIA_TYPE, exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java
deleted file mode 100644
index 806fc67..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.taverna.server.localworker.remote.ImplementationException;
-
-public class ImplementationProblemHandler extends HandlerCore implements
-		ExceptionMapper<ImplementationException> {
-	@Override
-	public Response toResponse(ImplementationException exception) {
-		return respond(INTERNAL_SERVER_ERROR, exception);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java
deleted file mode 100644
index 6b4470b..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static java.lang.Long.parseLong;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.List;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.commons.logging.Log;
-
-/**
- * Maps a stream from a client into a bounded ordinary input stream that the
- * webapp can work with more easily.
- * 
- * @author Donal Fellows
- */
-@Provider
-@Consumes(APPLICATION_OCTET_STREAM)
-public class InputStreamMessageHandler implements
-		MessageBodyReader<InputStream> {
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return InputStream.class.isAssignableFrom(type);
-	}
-
-	@Override
-	public InputStream readFrom(Class<InputStream> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		return new TransferStream(entityStream,
-				httpHeaders.get("Content-Length"));
-	}
-}
-
-/**
- * The actual transfer thunk.
- * 
- * @author Donal Fellows
- */
-class TransferStream extends InputStream {
-	private Log log = getLog("Taverna.Server.Handlers");
-
-	public TransferStream(InputStream entityStream, List<String> contentLength) {
-		this.entityStream = new BufferedInputStream(entityStream);
-		if (contentLength != null && contentLength.size() > 0) {
-			this.limit = parseLong(contentLength.get(0));
-			if (log.isDebugEnabled())
-				log.debug("will attempt to transfer " + this.limit + " bytes");
-		} else {
-			this.limit = -1;
-			if (log.isDebugEnabled())
-				log.debug("will attempt to transfer until EOF");
-		}
-	}
-
-	InputStream entityStream;
-	long limit;
-	long doneBytes = 0;
-
-	@Override
-	public int read() throws IOException {
-		if (limit >= 0 && doneBytes >= limit)
-			return -1;
-		int result = entityStream.read();
-		if (result >= 0)
-			doneBytes++;
-		return result;
-	}
-
-	@Override
-	public int read(byte[] ary, int off, int len) throws IOException {
-		if (limit >= 0) {
-			if (doneBytes >= limit)
-				return -1;
-			if (doneBytes + len > limit)
-				len = (int) (limit - doneBytes);
-		}
-		int readBytes = entityStream.read(ary, off, len);
-		if (readBytes >= 0)
-			doneBytes += readBytes;
-		return readBytes;
-	}
-
-	@Override
-	public void close() throws IOException {
-		entityStream.close();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java
deleted file mode 100644
index 7208aa4..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-
-@Provider
-public class InvalidCredentialHandler extends HandlerCore implements
-		ExceptionMapper<InvalidCredentialException> {
-	@Override
-	public Response toResponse(InvalidCredentialException exn) {
-		return respond(BAD_REQUEST, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java
deleted file mode 100644
index cf5952e..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-import javax.xml.bind.JAXBException;
-
-@Provider
-public class JAXBExceptionHandler extends HandlerCore implements
-		ExceptionMapper<JAXBException> {
-	@Override
-	public Response toResponse(JAXBException exn) {
-		return respond(BAD_REQUEST, "APIEpicFail: " + exn.getErrorCode(), exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java
deleted file mode 100644
index 00457fe..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
-import static javax.ws.rs.core.Response.notAcceptable;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.rest.TavernaServerDirectoryREST.NegotiationFailedException;
-
-@Provider
-public class NegotiationFailedHandler implements
-		ExceptionMapper<NegotiationFailedException> {
-	@Override
-	public Response toResponse(NegotiationFailedException exn) {
-		return notAcceptable(exn.accepted).type(TEXT_PLAIN)
-				.entity(exn.getMessage()).build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java
deleted file mode 100644
index f20f876..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoCreateException;
-
-@Provider
-public class NoCreateHandler extends HandlerCore implements
-		ExceptionMapper<NoCreateException> {
-	@Override
-	public Response toResponse(NoCreateException exn) {
-		return respond(SERVICE_UNAVAILABLE, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java
deleted file mode 100644
index 6644901..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.taverna.server.master.exceptions.NoCredentialException;
-
-public class NoCredentialHandler extends HandlerCore implements
-		ExceptionMapper<NoCredentialException> {
-	@Override
-	public Response toResponse(NoCredentialException exn) {
-		return respond(NOT_FOUND, exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java
deleted file mode 100644
index 2c0f5a9..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoDestroyException;
-
-@Provider
-public class NoDestroyHandler extends HandlerCore implements
-		ExceptionMapper<NoDestroyException> {
-	@Override
-	public Response toResponse(NoDestroyException exn) {
-		return respond(FORBIDDEN, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
deleted file mode 100644
index 2f72487..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-
-@Provider
-public class NoDirectoryEntryHandler extends HandlerCore implements
-		ExceptionMapper<NoDirectoryEntryException> {
-	@Override
-	public Response toResponse(NoDirectoryEntryException exn) {
-		return respond(NOT_FOUND, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java
deleted file mode 100644
index e119b60..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoListenerException;
-
-@Provider
-public class NoListenerHandler extends HandlerCore implements
-		ExceptionMapper<NoListenerException> {
-	@Override
-	public Response toResponse(NoListenerException exn) {
-		return respond(BAD_REQUEST, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java
deleted file mode 100644
index 2d5dde3..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoUpdateException;
-
-@Provider
-public class NoUpdateHandler extends HandlerCore implements
-		ExceptionMapper<NoUpdateException> {
-	@Override
-	public Response toResponse(NoUpdateException exn) {
-		return respond(FORBIDDEN, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java
deleted file mode 100644
index baeb6aa..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.taverna.server.master.exceptions.NotOwnerException;
-
-public class NotOwnerHandler extends HandlerCore implements
-		ExceptionMapper<NotOwnerException> {
-	@Override
-	public Response toResponse(NotOwnerException exn) {
-		return respond(FORBIDDEN, exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java
deleted file mode 100644
index 9e142f3..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.OverloadedException;
-
-@Provider
-public class OverloadedHandler extends HandlerCore implements
-		ExceptionMapper<OverloadedException> {
-	@Override
-	public Response toResponse(OverloadedException exn) {
-		return respond(SERVICE_UNAVAILABLE, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java
deleted file mode 100644
index d7a4afc..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-
-import org.taverna.server.master.common.Permission;
-
-/**
- * Handler that allows CXF to send and receive {@linkplain Permission
- * permissions} as plain text directly.
- * 
- * @author Donal Fellows
- */
-public class PermissionHandler implements MessageBodyReader<Permission>,
-		MessageBodyWriter<Permission> {
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return type.isAssignableFrom(Permission.class)
-				&& mediaType.isCompatible(TEXT_PLAIN_TYPE);
-	}
-
-	@Override
-	public long getSize(Permission t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return t.toString().length();
-	}
-
-	@Override
-	public void writeTo(Permission t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		new OutputStreamWriter(entityStream).write(t.toString());
-	}
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return type.isAssignableFrom(Permission.class)
-				&& mediaType.isCompatible(TEXT_PLAIN_TYPE);
-	}
-
-	@Override
-	public Permission readFrom(Class<Permission> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		char[] cbuf = new char[7];
-		int len = new InputStreamReader(entityStream).read(cbuf);
-		if (len < 0)
-			throw new IllegalArgumentException("no entity supplied");
-		return Permission.valueOf(new String(cbuf, 0, len));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
deleted file mode 100644
index cf1ccdf..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.common.Workflow;
-
-import org.apache.taverna.scufl2.api.io.ReaderException;
-import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
-import org.apache.taverna.scufl2.api.io.WriterException;
-
-/**
- * Handler that allows a .scufl2 document to be read from and written to a REST
- * message directly.
- * 
- * @author Donal Fellows
- */
-@Provider
-public class Scufl2DocumentHandler implements MessageBodyReader<Workflow>,
-		MessageBodyWriter<Workflow> {
-	private static final MediaType SCUFL2_TYPE = new MediaType("application",
-			"vnd.taverna.scufl2.workflow-bundle");
-	public static final String SCUFL2 = "application/vnd.taverna.scufl2.workflow-bundle";
-	private WorkflowBundleIO io = new WorkflowBundleIO();
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (type.isAssignableFrom(Workflow.class))
-			return mediaType.isCompatible(SCUFL2_TYPE);
-		return false;
-	}
-
-	@Override
-	public Workflow readFrom(Class<Workflow> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		try {
-			return new Workflow(io.readBundle(entityStream, SCUFL2));
-		} catch (ReaderException e) {
-			throw new WebApplicationException(e, 403);
-		}
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (Workflow.class.isAssignableFrom(type))
-			return mediaType.isCompatible(SCUFL2_TYPE);
-		return false;
-	}
-
-	@Override
-	public long getSize(Workflow workflow, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(Workflow workflow, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		try {
-			io.writeBundle(workflow.getScufl2Workflow(), entityStream, SCUFL2);
-		} catch (WriterException e) {
-			throw new WebApplicationException(e);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
deleted file mode 100644
index 1f6d328..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import org.taverna.server.master.common.Workflow;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-/**
- * Handler that allows a .t2flow document to be read from and written to a REST
- * message directly.
- * 
- * @author Donal Fellows
- */
-@Provider
-public class T2FlowDocumentHandler implements MessageBodyReader<Workflow>,
-		MessageBodyWriter<Workflow> {
-	private static final MediaType T2FLOW_TYPE = new MediaType("application",
-			"vnd.taverna.t2flow+xml");
-	public static final String T2FLOW = "application/vnd.taverna.t2flow+xml";
-	public static final String T2FLOW_ROOTNAME = "workflow";
-	public static final String T2FLOW_NS = "http://taverna.sf.net/2008/xml/t2flow";
-	private DocumentBuilderFactory db;
-	private TransformerFactory transformer;
-
-	public T2FlowDocumentHandler() throws ParserConfigurationException,
-			TransformerConfigurationException {
-		db = DocumentBuilderFactory.newInstance();
-		db.setNamespaceAware(true);
-		transformer = TransformerFactory.newInstance();
-	}
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (type.isAssignableFrom(Workflow.class))
-			return mediaType.isCompatible(T2FLOW_TYPE);
-		return false;
-	}
-
-	@Override
-	public Workflow readFrom(Class<Workflow> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		Document doc;
-		try {
-			doc = db.newDocumentBuilder().parse(entityStream);
-		} catch (SAXException e) {
-			throw new WebApplicationException(e, 403);
-		} catch (ParserConfigurationException e) {
-			throw new WebApplicationException(e);
-		}
-		Workflow workflow = new Workflow(doc.getDocumentElement());
-		if (doc.getDocumentElement().getNamespaceURI().equals(T2FLOW_NS)
-				&& doc.getDocumentElement().getNodeName()
-						.equals(T2FLOW_ROOTNAME))
-			return workflow;
-		throw new WebApplicationException(Response.status(403)
-				.entity("invalid T2flow document; bad root element")
-				.type("text/plain").build());
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (Workflow.class.isAssignableFrom(type))
-			return mediaType.isCompatible(T2FLOW_TYPE);
-		return false;
-	}
-
-	@Override
-	public long getSize(Workflow workflow, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(Workflow workflow, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		try {
-			transformer.newTransformer().transform(
-					new DOMSource(workflow.getT2flowWorkflow()),
-					new StreamResult(entityStream));
-		} catch (TransformerException e) {
-			if (e.getCause() != null && e.getCause() instanceof IOException)
-				throw (IOException) e.getCause();
-			throw new WebApplicationException(e);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java
deleted file mode 100644
index 453ac73..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.status;
-import static org.taverna.server.master.rest.handler.URIListHandler.URI_LIST;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-/**
- * Deserialization and serialization engine for the <tt>{@value #URI_LIST}</tt>
- * content type.
- * 
- * @author Donal Fellows
- */
-@Provider
-@Consumes(URI_LIST)
-public class URIListHandler implements MessageBodyReader<List<URI>>,
-		MessageBodyWriter<List<URI>> {
-	/** The content type we handle. */
-	public static final String URI_LIST = "text/uri-list";
-	private static final MediaType URILIST = new MediaType("text", "uri-list");
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return type.isAssignableFrom(ArrayList.class)
-				&& genericType instanceof ParameterizedType
-				&& ((Class<?>) ((ParameterizedType) genericType)
-						.getActualTypeArguments()[0])
-						.isAssignableFrom(URI.class)
-				&& URILIST.isCompatible(mediaType);
-	}
-
-	@Override
-	public List<URI> readFrom(Class<List<URI>> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		String enc = mediaType.getParameters().get("encoding");
-		Charset c = (enc == null) ? Charset.defaultCharset() : Charset
-				.forName(enc);
-		BufferedReader br = new BufferedReader(new InputStreamReader(
-				entityStream, c));
-		ArrayList<URI> uris = new ArrayList<>();
-		String line;
-		while ((line = br.readLine()) != null) {
-			if (line.startsWith("#"))
-				continue;
-			try {
-				uris.add(new URI(line));
-			} catch (URISyntaxException e) {
-				throw new WebApplicationException(e, status(422).entity(
-						"ill-formed URI").build());
-			}
-		}
-		return uris;
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return List.class.isAssignableFrom(type)
-				&& genericType instanceof ParameterizedType
-				&& ((ParameterizedType) genericType).getActualTypeArguments()[0] == URI.class
-				&& URILIST.isCompatible(mediaType);
-	}
-
-	@Override
-	public long getSize(List<URI> list, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	private static final String PREFERRED_ENCODING = "UTF-8";
-
-	@Override
-	public void writeTo(List<URI> list, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException {
-		String encoding = mediaType.getParameters().get("encoding");
-		if (encoding == null) {
-			encoding = PREFERRED_ENCODING;
-			httpHeaders.putSingle("Content-Type", URI_LIST + ";encoding="
-					+ encoding);
-		}
-		BufferedWriter w = new BufferedWriter(new OutputStreamWriter(
-				entityStream, encoding));
-		for (URI uri : list) {
-			w.write(uri.toString());
-			w.newLine();
-		}
-		w.flush();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java
deleted file mode 100644
index 4d5c6e8..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.UnknownRunException;
-
-@Provider
-public class UnknownRunHandler extends HandlerCore implements
-		ExceptionMapper<UnknownRunException> {
-	@Override
-	public Response toResponse(UnknownRunException exn) {
-		return respond(NOT_FOUND, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java
deleted file mode 100644
index 69e526d..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static org.apache.commons.io.IOUtils.copy;
-import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.interfaces.Directory.ZipStream;
-
-/**
- * How to write a ZIP file as the result entity of a request.
- * 
- * @author Donal Fellows
- */
-@Provider
-@Produces("application/zip")
-public class ZipStreamHandler implements MessageBodyWriter<ZipStream> {
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return ZipStream.class.isAssignableFrom(type)
-				&& mediaType.equals(APPLICATION_ZIP_TYPE);
-	}
-
-	@Override
-	public long getSize(ZipStream t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(ZipStream zipStream, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		copy(zipStream, entityStream);
-	}
-}



[12/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java
deleted file mode 100644
index a41e23b..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- */
-package org.taverna.server.master.notification;
-/*
- * 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.
- */
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.joda.time.DateTime;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * Rate-limiting support. Some message fabrics simply should not be used to send
- * a lot of messages.
- * 
- * @author Donal Fellows
- */
-public abstract class RateLimitedDispatcher implements MessageDispatcher {
-	/** Pre-configured logger. */
-	protected Log log = LogFactory.getLog("Taverna.Server.Notification");
-	private int cooldownSeconds;
-	private Map<String, DateTime> lastSend = new HashMap<>();
-
-	String valid(String value, String def) {
-		if (value == null || value.trim().isEmpty()
-				|| value.trim().startsWith("${"))
-			return def;
-		else
-			return value.trim();
-	}
-
-	/**
-	 * Set how long must elapse between updates to the status of any particular
-	 * user. Calls before that time are just silently dropped.
-	 * 
-	 * @param cooldownSeconds
-	 *            Time to elapse, in seconds.
-	 */
-	public void setCooldownSeconds(int cooldownSeconds) {
-		this.cooldownSeconds = cooldownSeconds;
-	}
-
-	/**
-	 * Test whether the rate limiter allows the given user to send a message.
-	 * 
-	 * @param who
-	 *            Who wants to send the message?
-	 * @return <tt>true</tt> iff they are permitted.
-	 */
-	protected boolean isSendAllowed(String who) {
-		DateTime now = new DateTime();
-		synchronized (lastSend) {
-			DateTime last = lastSend.get(who);
-			if (last != null) {
-				if (!now.isAfter(last.plusSeconds(cooldownSeconds)))
-					return false;
-			}
-			lastSend.put(who, now);
-		}
-		return true;
-	}
-
-	@Override
-	public void dispatch(TavernaRun ignored, String messageSubject,
-			String messageContent, String target) throws Exception {
-		if (isSendAllowed(target))
-			dispatch(messageSubject, messageContent, target);
-	}
-
-	/**
-	 * Dispatch a message to a recipient that doesn't care what produced it.
-	 * 
-	 * @param messageSubject
-	 *            The subject of the message to send.
-	 * @param messageContent
-	 *            The plain-text content of the message to send.
-	 * @param target
-	 *            A description of where it is to go.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	public abstract void dispatch(String messageSubject, String messageContent,
-			String target) throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java
deleted file mode 100644
index 559f111..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- */
-package org.taverna.server.master.notification;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.defaults.Default.SMS_GATEWAY_URL;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.message.BasicNameValuePair;
-import org.springframework.beans.factory.annotation.Required;
-
-/**
- * Dispatch termination messages via SMS.
- * 
- * @author Donal Fellows
- */
-public class SMSDispatcher extends RateLimitedDispatcher {
-	@Override
-	public String getName() {
-		return "sms";
-	}
-
-	private CloseableHttpClient client;
-	private URI service;
-	private String user = "", pass = "";
-	private String usernameField = "username", passwordField = "password",
-			destinationField = "to", messageField = "text";
-
-	/**
-	 * @param usernameField
-	 *            The name of the field that conveys the sending username; this
-	 *            is the <i>server</i>'s identity.
-	 */
-	@Required
-	public void setUsernameField(String usernameField) {
-		this.usernameField = usernameField;
-	}
-
-	/**
-	 * @param passwordField
-	 *            The field holding the password to authenticate the server to
-	 *            the SMS gateway.
-	 */
-	@Required
-	public void setPasswordField(String passwordField) {
-		this.passwordField = passwordField;
-	}
-
-	/**
-	 * @param destinationField
-	 *            The field holding the number to send the SMS to.
-	 */
-	@Required
-	public void setDestinationField(String destinationField) {
-		this.destinationField = destinationField;
-	}
-
-	/**
-	 * @param messageField
-	 *            The field holding the plain-text message to send.
-	 */
-	@Required
-	public void setMessageField(String messageField) {
-		this.messageField = messageField;
-	}
-
-	public void setService(String serviceURL) {
-		String s = valid(serviceURL, "");
-		if (s.isEmpty()) {
-			log.warn("did not get sms.service from servlet config; using default ("
-					+ SMS_GATEWAY_URL + ")");
-			s = SMS_GATEWAY_URL;
-		}
-		try {
-			service = new URI(s);
-		} catch (URISyntaxException e) {
-			service = null;
-		}
-	}
-
-	public void setUser(String user) {
-		this.user = valid(user, "");
-	}
-
-	public void setPassword(String pass) {
-		this.pass = valid(pass, "");
-	}
-
-	@PostConstruct
-	void init() {
-		client = HttpClientBuilder.create().build();
-	}
-
-	@PreDestroy
-	void close() throws IOException {
-		try {
-			if (client != null)
-				client.close();
-		} finally {
-			client = null;
-		}
-	}
-
-	@Override
-	public boolean isAvailable() {
-		return service != null && !user.isEmpty() && !pass.isEmpty();
-	}
-
-	@Override
-	public void dispatch(String messageSubject, String messageContent,
-			String targetParameter) throws Exception {
-		// Sanity check
-		if (!targetParameter.matches("[^0-9]+"))
-			throw new Exception("invalid phone number");
-
-		if (!isSendAllowed("anyone"))
-			return;
-
-		// Build the message to send
-		List<NameValuePair> params = new ArrayList<>();
-		params.add(new BasicNameValuePair(usernameField, user));
-		params.add(new BasicNameValuePair(passwordField, pass));
-		params.add(new BasicNameValuePair(destinationField, targetParameter));
-		params.add(new BasicNameValuePair(messageField, messageContent));
-
-		// Send the message
-		HttpPost post = new HttpPost(service);
-		post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
-		HttpResponse response = client.execute(post);
-
-		// Log the response
-		HttpEntity entity = response.getEntity();
-		if (entity != null)
-			try (BufferedReader e = new BufferedReader(new InputStreamReader(
-					entity.getContent()))) {
-				log.info(e.readLine());
-			}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java
deleted file mode 100644
index a0269a5..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- */
-package org.taverna.server.master.notification;
-/*
- * 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.
- */
-
-import java.util.Properties;
-
-import twitter4j.Twitter;
-import twitter4j.TwitterFactory;
-import twitter4j.conf.Configuration;
-import twitter4j.conf.PropertyConfiguration;
-import twitter4j.auth.AuthorizationFactory;
-
-/**
- * Super simple-minded twitter dispatcher. You need to tell it your consumer key
- * and secret as part of the connection parameters, for example via a dispatcher
- * URN of "<tt>twitter:fred:bloggs</tt>" where <tt>fred</tt> is the key and
- * <tt>bloggs</tt> is the secret.
- * 
- * @author Donal Fellows
- */
-public class TwitterDispatcher extends RateLimitedDispatcher {
-	@Override
-	public String getName() {
-		return "twitter";
-	}
-
-	public static final int MAX_MESSAGE_LENGTH = 140;
-	public static final char ELLIPSIS = '\u2026';
-
-	private String token = "";
-	private String secret = "";
-
-	public void setAccessToken(String token) {
-		this.token = valid(token, "");
-	}
-
-	public void setAccessSecret(String secret) {
-		this.secret = valid(secret, "");
-	}
-
-	private Properties getConfig() throws NotConfiguredException {
-		if (token.isEmpty() || secret.isEmpty())
-			throw new NotConfiguredException();
-		Properties p = new Properties();
-		p.setProperty(ACCESS_TOKEN_PROP, token);
-		p.setProperty(ACCESS_SECRET_PROP, secret);
-		return p;
-	}
-
-	public static final String ACCESS_TOKEN_PROP = "oauth.accessToken";
-	public static final String ACCESS_SECRET_PROP = "oauth.accessTokenSecret";
-
-	private Twitter getTwitter(String key, String secret) throws Exception {
-		if (key.isEmpty() || secret.isEmpty())
-			throw new NoCredentialsException();
-
-		Properties p = getConfig();
-		p.setProperty("oauth.consumerKey", key);
-		p.setProperty("oauth.consumerSecret", secret);
-
-		Configuration config = new PropertyConfiguration(p);
-		TwitterFactory factory = new TwitterFactory(config);
-		Twitter t = factory.getInstance(AuthorizationFactory
-				.getInstance(config));
-		// Verify that we can connect!
-		t.getOAuthAccessToken();
-		return t;
-	}
-
-	// TODO: Get secret from credential manager
-	@Override
-	public void dispatch(String messageSubject, String messageContent,
-			String targetParameter) throws Exception {
-		// messageSubject ignored
-		String[] target = targetParameter.split(":", 2);
-		if (target == null || target.length != 2)
-			throw new Exception("missing consumer key or secret");
-		String who = target[0];
-		if (!isSendAllowed(who))
-			return;
-		Twitter twitter = getTwitter(who, target[1]);
-
-		if (messageContent.length() > MAX_MESSAGE_LENGTH)
-			messageContent = messageContent
-					.substring(0, MAX_MESSAGE_LENGTH - 1) + ELLIPSIS;
-		twitter.updateStatus(messageContent);
-	}
-
-	@Override
-	public boolean isAvailable() {
-		try {
-			// Try to create the configuration and push it through as far as
-			// confirming that we can build an access object (even if it isn't
-			// bound to a user)
-			new TwitterFactory(new PropertyConfiguration(getConfig()))
-					.getInstance();
-			return true;
-		} catch (Exception e) {
-			return false;
-		}
-	}
-
-	/**
-	 * Indicates that the dispatcher has not been configured with service
-	 * credentials.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@SuppressWarnings("serial")
-	public static class NotConfiguredException extends Exception {
-		NotConfiguredException() {
-			super("not configured with xAuth key and secret; "
-					+ "dispatch not possible");
-		}
-	}
-
-	/**
-	 * Indicates that the user did not supply their credentials.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@SuppressWarnings("serial")
-	public static class NoCredentialsException extends Exception {
-		NoCredentialsException() {
-			super("no consumer key and secret present; "
-					+ "dispatch not possible");
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java
deleted file mode 100644
index eda6d9d..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- */
-package org.taverna.server.master.notification.atom;
-/*
- * 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.
- */
-
-import static java.lang.String.format;
-import static java.util.UUID.randomUUID;
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.common.Uri.secure;
-
-import java.net.URI;
-import java.util.Date;
-
-import javax.annotation.security.RolesAllowed;
-import javax.servlet.ServletContext;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.model.Feed;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.web.context.ServletContextAware;
-import org.taverna.server.master.TavernaServerSupport;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.rest.TavernaServerREST.EventFeed;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * Simple REST handler that allows an Atom feed to be served up of events
- * generated by workflow runs.
- * 
- * @author Donal Fellows
- */
-public class AtomFeed implements EventFeed, UriBuilderFactory,
-		ServletContextAware {
-	/**
-	 * The name of a parameter that states what address we should claim that the
-	 * feed's internally-generated URIs are relative to. If not set, a default
-	 * will be guessed.
-	 */
-	public static final String PREFERRED_URI_PARAM = "taverna.preferredUserUri";
-	private EventDAO eventSource;
-	private TavernaServerSupport support;
-	private URI baseURI;
-	private Abdera abdera;
-	private String feedLanguage = "en";
-	private String uuid = randomUUID().toString();
-
-	@Required
-	public void setEventSource(EventDAO eventSource) {
-		this.eventSource = eventSource;
-	}
-
-	@Required
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	public void setFeedLanguage(String language) {
-		this.feedLanguage = language;
-	}
-
-	public String getFeedLanguage() {
-		return feedLanguage;
-	}
-
-	@Required
-	public void setAbdera(Abdera abdera) {
-		this.abdera = abdera;
-	}
-
-	@Override
-	@CallCounted
-	@RolesAllowed(USER)
-	public Feed getFeed(UriInfo ui) {
-		Feed feed = abdera.getFactory().newFeed();
-		feed.setTitle("events relating to workflow runs").setLanguage(
-				feedLanguage);
-		String user = support.getPrincipal().toString()
-				.replaceAll("[^A-Za-z0-9]+", "");
-		feed.setId(format("urn:taverna-server:%s:%s", uuid, user));
-		org.joda.time.DateTime modification = null;
-		for (Event e : eventSource.getEvents(support.getPrincipal())) {
-			if (modification == null || e.getPublished().isAfter(modification))
-				modification = e.getPublished();
-			feed.addEntry(e.getEntry(abdera, feedLanguage));
-		}
-		if (modification == null)
-			feed.setUpdated(new Date());
-		else
-			feed.setUpdated(modification.toDate());
-		feed.addLink(ui.getAbsolutePath().toASCIIString(), "self");
-		return feed;
-	}
-
-	@Override
-	@CallCounted
-	@RolesAllowed(USER)
-	public Entry getEvent(String id) {
-		return eventSource.getEvent(support.getPrincipal(), id).getEntry(
-				abdera, feedLanguage);
-	}
-
-	@Override
-	public UriBuilder getRunUriBuilder(TavernaRun run) {
-		return secure(fromUri(getBaseUriBuilder().path("runs/{uuid}").build(
-				run.getId())));
-	}
-
-	@Override
-	public UriBuilder getBaseUriBuilder() {
-		return secure(fromUri(baseURI));
-	}
-
-	@Override
-	public String resolve(String uri) {
-		if (uri == null)
-			return null;
-		return secure(baseURI, uri).toString();
-	}
-
-	@Override
-	public void setServletContext(ServletContext servletContext) {
-		String base = servletContext.getInitParameter(PREFERRED_URI_PARAM);
-		if (base == null)
-			base = servletContext.getContextPath() + "/rest";
-		baseURI = URI.create(base);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java
deleted file mode 100644
index f1a9d62..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- */
-package org.taverna.server.master.notification.atom;
-/*
- * 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.
- */
-
-import static java.util.UUID.randomUUID;
-
-import java.io.Serializable;
-import java.net.URI;
-import java.util.Date;
-
-import javax.jdo.annotations.Column;
-import javax.jdo.annotations.Index;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.Queries;
-import javax.jdo.annotations.Query;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.model.Entry;
-import org.joda.time.DateTime;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Parent class of all events that may appear on the feed for a workflow run.
- * 
- * @author Donal Fellows
- */
-@SuppressWarnings("serial")
-@PersistenceCapable(schema = "ATOM", table = "EVENTS")
-@Queries({
-		@Query(name = "eventsForUser", language = "SQL", value = "SELECT id FROM ATOM.EVENTS WHERE owner = ? ORDER BY published DESC", resultClass = String.class),
-		@Query(name = "eventForUserAndId", language = "SQL", value = "SELECT id FROM ATOM.EVENTS WHERE owner = ? AND id = ?", resultClass = String.class),
-		@Query(name = "eventsFromBefore", language = "SQL", value = "SELECT id FROM ATOM.EVENTS where published < ?", resultClass = String.class) })
-public class Event implements Serializable {
-	@Persistent(primaryKey = "true")
-	@Column(length = 48)
-	private String id;
-	@Persistent
-	private String owner;
-	@Persistent
-	@Index
-	private Date published;
-	@Persistent
-	private String message;
-	@Persistent
-	private String title;
-	@Persistent
-	private String link;
-
-	Event() {
-	}
-
-	/**
-	 * Initialise the identity of this event and the point at which it was
-	 * published.
-	 * 
-	 * @param idPrefix
-	 *            A prefix for the identity of this event.
-	 * @param owner
-	 *            Who is the owner of this event.
-	 */
-	Event(String idPrefix, URI workflowLink, UsernamePrincipal owner,
-			String title, String message) {
-		id = idPrefix + "." + randomUUID().toString();
-		published = new Date();
-		this.owner = owner.getName();
-		this.title = title;
-		this.message = message;
-		this.link = workflowLink.toASCIIString();
-	}
-
-	public final String getId() {
-		return id;
-	}
-
-	public final String getOwner() {
-		return owner;
-	}
-
-	public final DateTime getPublished() {
-		return new DateTime(published);
-	}
-
-	public String getMessage() {
-		return message;
-	}
-
-	public String getTitle() {
-		return title;
-	}
-
-	public String getLink() {
-		return link;
-	}
-
-	public Entry getEntry(Abdera abdera, String language) {
-		Entry entry = abdera.getFactory().newEntry();
-		entry.setId(id);
-		entry.setPublished(published);
-		entry.addAuthor(owner).setLanguage(language);
-		entry.setUpdated(published);
-		entry.setTitle(title).setLanguage(language);
-		entry.addLink(link, "related").setTitle("workflow run");
-		entry.setContent(message).setLanguage(language);
-		return entry;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java
deleted file mode 100644
index 8bec456..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- */
-package org.taverna.server.master.notification.atom;
-/*
- * 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.
- */
-
-import static java.lang.Thread.interrupted;
-import static java.lang.Thread.sleep;
-import static java.util.Arrays.asList;
-
-import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PreDestroy;
-import javax.jdo.annotations.PersistenceAware;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.joda.time.DateTime;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.JDOSupport;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * The database interface that supports the event feed.
- * 
- * @author Donal Fellows
- */
-@PersistenceAware
-public class EventDAO extends JDOSupport<Event> implements MessageDispatcher {
-	public EventDAO() {
-		super(Event.class);
-	}
-
-	@Override
-	public String getName() {
-		return "atom";
-	}
-
-	private Log log = LogFactory.getLog("Taverna.Server.Atom");
-	private UriBuilderFactory ubf;
-	private int expiryAgeDays;
-
-	@Required
-	public void setExpiryAgeDays(int expiryAgeDays) {
-		this.expiryAgeDays = expiryAgeDays;
-	}
-
-	@Required
-	public void setUriBuilderFactory(UriBuilderFactory ubf) {
-		this.ubf = ubf;
-	}
-
-	/**
-	 * Get the given user's list of events.
-	 * 
-	 * @param user
-	 *            The identity of the user to get the events for.
-	 * @return A copy of the list of events currently known about.
-	 */
-	@Nonnull
-	@WithinSingleTransaction
-	public List<Event> getEvents(@Nonnull UsernamePrincipal user) {
-		List<String> ids = eventsForUser(user);
-		if (log.isDebugEnabled())
-			log.debug("found " + ids.size() + " events for user " + user);
-
-		List<Event> result = new ArrayList<>();
-		for (String id : ids) {
-			Event event = getById(id);
-			result.add(detach(event));
-		}
-		return result;
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> eventsForUser(UsernamePrincipal user) {
-		return (List<String>) namedQuery("eventsForUser").execute(
-				user.getName());
-	}
-
-	/**
-	 * Get a particular event.
-	 * 
-	 * @param user
-	 *            The identity of the user to get the event for.
-	 * @param id
-	 *            The handle of the event to look up.
-	 * @return A copy of the event.
-	 */
-	@Nonnull
-	@WithinSingleTransaction
-	public Event getEvent(@Nonnull UsernamePrincipal user, @Nonnull String id) {
-		List<String> ids = eventsForUserAndId(user, id);
-		if (log.isDebugEnabled())
-			log.debug("found " + ids.size() + " events for user " + user
-					+ " with id = " + id);
-
-		if (ids.size() != 1)
-			throw new IllegalArgumentException("no such id");
-		return detach(getById(ids.get(0)));
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> eventsForUserAndId(UsernamePrincipal user, String id) {
-		return (List<String>) namedQuery("eventForUserAndId").execute(
-				user.getName(), id);
-	}
-
-	/**
-	 * Delete a particular event.
-	 * 
-	 * @param id
-	 *            The identifier of the event to delete.
-	 */
-	@WithinSingleTransaction
-	public void deleteEventById(@Nonnull String id) {
-		delete(getById(id));
-	}
-
-	/**
-	 * Delete all events that have expired.
-	 */
-	@WithinSingleTransaction
-	public void deleteExpiredEvents() {
-		Date death = new DateTime().plusDays(-expiryAgeDays).toDate();
-		death = new Timestamp(death.getTime()); // UGLY SQL HACK
-
-		List<String> ids = eventsFromBefore(death);
-		if (log.isDebugEnabled() && !ids.isEmpty())
-			log.debug("found " + ids.size()
-					+ " events to be squelched (older than " + death + ")");
-
-		for (String id : ids)
-			delete(getById(id));
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> eventsFromBefore(Date death) {
-		return (List<String>) namedQuery("eventsFromBefore").execute(death);
-	}
-
-	@Override
-	public boolean isAvailable() {
-		return true;
-	}
-
-	private BlockingQueue<Event> insertQueue = new ArrayBlockingQueue<>(16);
-
-	@Override
-	public void dispatch(TavernaRun originator, String messageSubject,
-			String messageContent, String targetParameter) throws Exception {
-		insertQueue.put(new Event("finish", ubf.getRunUriBuilder(originator)
-				.build(), originator.getSecurityContext().getOwner(),
-				messageSubject, messageContent));
-	}
-
-	public void started(TavernaRun originator, String messageSubject,
-			String messageContent) throws InterruptedException {
-		insertQueue.put(new Event("start", ubf.getRunUriBuilder(originator)
-				.build(), originator.getSecurityContext().getOwner(),
-				messageSubject, messageContent));
-	}
-
-	private Thread eventDaemon;
-	private boolean shuttingDown = false;
-
-	@Required
-	public void setSelf(final EventDAO dao) {
-		eventDaemon = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					while (!shuttingDown && !interrupted()) {
-						transferEvents(dao, new ArrayList<Event>(
-								asList(insertQueue.take())));
-						sleep(5000);
-					}
-				} catch (InterruptedException e) {
-				} finally {
-					transferEvents(dao, new ArrayList<Event>());
-				}
-			}
-		}, "ATOM event daemon");
-		eventDaemon.setContextClassLoader(null);
-		eventDaemon.setDaemon(true);
-		eventDaemon.start();
-	}
-
-	private void transferEvents(EventDAO dao, List<Event> e) {
-		insertQueue.drainTo(e);
-		dao.storeEvents(e);
-	}
-
-	@PreDestroy
-	void stopDaemon() {
-		shuttingDown = true;
-		if (eventDaemon != null)
-			eventDaemon.interrupt();
-	}
-
-	@WithinSingleTransaction
-	protected void storeEvents(List<Event> events) {
-		for (Event e : events)
-			persist(e);
-		log.info("stored " + events.size() + " notification events");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java
deleted file mode 100644
index 0a1a52f..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- */
-/**
- * This package contains the Atom feed implementation within Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = FEED, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.notification.atom;
-/*
- * 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.
- */
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.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/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java
deleted file mode 100644
index 43335cf..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- */
-/**
- * The notification fabric and implementations of notification dispatchers
- * that support subscription.
- */
-package org.taverna.server.master.notification;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/package-info.java
deleted file mode 100644
index d912ac8..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- */
-/**
- * The core of the implementation of Taverna Server, including the
- * implementations of the SOAP and REST interfaces.
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java
deleted file mode 100644
index d9aef82..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.MediaType.APPLICATION_ATOM_XML;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
-import static javax.ws.rs.core.MediaType.APPLICATION_XML;
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
-
-/**
- * Miscellaneous content type constants.
- * 
- * @author Donal Fellows
- */
-interface ContentTypes {
-	static final String URI_LIST = "text/uri-list";
-	static final String ZIP = "application/zip";
-	static final String TEXT = TEXT_PLAIN;
-	static final String XML = APPLICATION_XML;
-	static final String JSON = APPLICATION_JSON;
-	static final String BYTES = APPLICATION_OCTET_STREAM;
-	static final String ATOM = APPLICATION_ATOM_XML;
-	static final String ROBUNDLE = "application/vnd.wf4ever.robundle+zip";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java
deleted file mode 100644
index 42d4b0e..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Uri.secure;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlElementRef;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-
-/**
- * The result of a RESTful operation to list the contents of a directory. Done
- * with JAXB.
- * 
- * @author Donal Fellows
- */
-@XmlRootElement
-@XmlType(name = "DirectoryContents")
-@XmlSeeAlso(MakeOrUpdateDirEntry.class)
-public class DirectoryContents {
-	/**
-	 * The contents of the directory.
-	 */
-	@XmlElementRef
-	public List<DirEntryReference> contents;
-
-	/**
-	 * Make an empty directory description. Required for JAXB.
-	 */
-	public DirectoryContents() {
-		contents = new ArrayList<>();
-	}
-
-	/**
-	 * Make a directory description.
-	 * 
-	 * @param ui
-	 *            The factory for URIs.
-	 * @param collection
-	 *            The real directory contents that we are to describe.
-	 */
-	public DirectoryContents(UriInfo ui, Collection<DirectoryEntry> collection) {
-		contents = new ArrayList<>();
-		UriBuilder ub = secure(ui).path("{filename}");
-		for (DirectoryEntry e : collection)
-			contents.add(DirEntryReference.newInstance(ub, e));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java
deleted file mode 100644
index 6b7aaff..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.ok;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-/**
- * Representation of a segment of a file to be read by JAX-RS.
- * 
- * @author Donal Fellows
- */
-public class FileSegment {
-	/** The file to read a segment of. */
-	public final File file;
-	/** The offset of the first byte of the segment to read. */
-	public Integer from;
-	/** The offset of the first byte after the segment to read. */
-	public Integer to;
-
-	/**
-	 * Parse the HTTP Range header and determine what exact range of the file to
-	 * read.
-	 * 
-	 * @param f
-	 *            The file this refers to
-	 * @param range
-	 *            The content of the Range header.
-	 * @throws FilesystemAccessException
-	 *             If we can't determine the length of the file (shouldn't
-	 *             happen).
-	 */
-	public FileSegment(File f, String range) throws FilesystemAccessException {
-		file = f;
-		Matcher m = Pattern.compile("^\\s*bytes=(\\d*)-(\\d*)\\s*$").matcher(
-				range);
-		if (m.matches()) {
-			if (!m.group(1).isEmpty())
-				from = Integer.valueOf(m.group(1));
-			if (!m.group(2).isEmpty())
-				to = Integer.valueOf(m.group(2)) + 1;
-			int size = (int) f.getSize();
-			if (from == null) {
-				from = size - to;
-				to = size;
-			} else if (to == null)
-				to = size;
-			else if (to > size)
-				to = size;
-		}
-	}
-
-	/**
-	 * Convert to a response, as per RFC 2616.
-	 * 
-	 * @param type
-	 *            The expected type of the data.
-	 * @return A JAX-RS response.
-	 */
-	public Response toResponse(MediaType type) {
-		if (from == null && to == null)
-			return ok(file).type(type).build();
-		if (from >= to)
-			return ok("Requested range not satisfiable").status(416).build();
-		return ok(this).status(206).type(type).build();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java
deleted file mode 100644
index 69705d9..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.rest.ContentTypes.ATOM;
-
-import java.net.MalformedURLException;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Response;
-
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.model.Feed;
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-
-/**
- * A very stripped down ATOM feed for the interaction service.
- * 
- * @author Donal Fellows
- */
-public interface InteractionFeedREST {
-	/**
-	 * Get the feed document for this ATOM feed.
-	 * 
-	 * @return The feed.
-	 * @throws FilesystemAccessException
-	 *             If we can't read from the feed directory.
-	 * @throws NoDirectoryEntryException
-	 *             If something changes things under our feet.
-	 */
-	@GET
-	@Path("/")
-	@Produces(ATOM)
-	@Description("Get the feed document for this ATOM feed.")
-	Feed getFeed() throws FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Adds an entry to this ATOM feed.
-	 * 
-	 * @param entry
-	 *            The entry to create.
-	 * @return A redirect to the created entry.
-	 * @throws MalformedURLException
-	 *             If we have problems generating the URI of the entry.
-	 * @throws FilesystemAccessException
-	 *             If we can't create the feed entry file.
-	 * @throws NoDirectoryEntryException
-	 *             If things get changed under our feet.
-	 * @throws NoUpdateException
-	 *             If we don't have permission to change things relating to this
-	 *             run.
-	 */
-	@POST
-	@Path("/")
-	@Consumes(ATOM)
-	@Produces(ATOM)
-	@Description("Adds an entry to this ATOM feed.")
-	Response addEntry(Entry entry) throws MalformedURLException,
-			FilesystemAccessException, NoDirectoryEntryException,
-			NoUpdateException;
-
-	/** Handles the OPTIONS request. */
-	@OPTIONS
-	@Path("/")
-	@Description("Describes what HTTP operations are supported on the feed.")
-	Response feedOptions();
-
-	/**
-	 * Gets the content of an entry in this ATOM feed.
-	 * 
-	 * @param id
-	 *            The ID of the entry to fetch.
-	 * @return The entry contents.
-	 * @throws FilesystemAccessException
-	 *             If we have problems reading the entry.
-	 * @throws NoDirectoryEntryException
-	 *             If we can't find the entry to read.
-	 */
-	@GET
-	@Path("{id}")
-	@Produces(ATOM)
-	@Description("Get the entry with a particular ID within this ATOM feed.")
-	Entry getEntry(@PathParam("id") String id)
-			throws FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Delete an entry from this ATOM feed.
-	 * 
-	 * @param id
-	 *            The ID of the entry to delete.
-	 * @return A simple message. Not very important!
-	 * @throws FilesystemAccessException
-	 *             If we have problems deleting the entry.
-	 * @throws NoDirectoryEntryException
-	 *             If we can't find the entry to delete.
-	 * @throws NoUpdateException
-	 *             If we don't have permission to alter things relating to this
-	 *             run.
-	 */
-	@DELETE
-	@Path("{id}")
-	@Produces("text/plain")
-	@Description("Deletes an entry from this ATOM feed.")
-	String deleteEntry(@PathParam("id") String id)
-			throws FilesystemAccessException, NoDirectoryEntryException,
-			NoUpdateException;
-
-	/** Handles the OPTIONS request. */
-	@OPTIONS
-	@Path("{id}")
-	@Description("Describes what HTTP operations are supported on an entry.")
-	Response entryOptions(@PathParam("{id}") String id);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java
deleted file mode 100644
index f877d7a..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-/**
- * Description of what sort of event listener to create and attach to a workflow
- * run. Bound via JAXB.
- * 
- * @author Donal Fellows
- */
-@XmlRootElement(name = "listenerDefinition")
-@XmlType(name="ListenerDefinition")
-public class ListenerDefinition {
-	/**
-	 * The type of event listener to create.
-	 */
-	@XmlAttribute
-	public String type;
-	/**
-	 * How the event listener should be configured.
-	 */
-	@XmlValue
-	public String configuration;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java
deleted file mode 100644
index 52e6d04..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-/**
- * The input to the REST interface for making directories and files, and
- * uploading file contents. Done with JAXB.
- * 
- * @author Donal Fellows
- */
-@XmlRootElement(name = "filesystemOperation")
-@XmlType(name = "FilesystemCreationOperation")
-@XmlSeeAlso( { MakeOrUpdateDirEntry.MakeDirectory.class,
-		MakeOrUpdateDirEntry.SetFileContents.class })
-public abstract class MakeOrUpdateDirEntry {
-	/**
-	 * The name of the file or directory that the operation applies to.
-	 */
-	@XmlAttribute
-	public String name;
-	/**
-	 * The contents of the file to upload.
-	 */
-	@XmlValue
-	public byte[] contents;
-
-	/**
-	 * Create a directory, described with JAXB. Should leave the
-	 * {@link MakeOrUpdateDirEntry#contents contents} field empty.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "mkdir")
-	@XmlType(name = "MakeDirectory")
-	public static class MakeDirectory extends MakeOrUpdateDirEntry {
-	}
-
-	/**
-	 * Create a file or set its contents, described with JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "upload")
-	@XmlType(name = "UploadFile")
-	public static class SetFileContents extends MakeOrUpdateDirEntry {
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java
deleted file mode 100644
index 1ed8a64..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static java.util.Collections.unmodifiableList;
-import static javax.ws.rs.core.MediaType.WILDCARD;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.BYTES;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.URI_LIST;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.ContentTypes.ZIP;
-
-import java.io.InputStream;
-import java.net.URI;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.PathSegment;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import javax.ws.rs.core.Variant;
-
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.File;
-
-/**
- * Representation of how a workflow run's working directory tree looks.
- * 
- * @author Donal Fellows
- */
-@RolesAllowed(USER)
-@Produces({ XML, JSON })
-@Consumes({ XML, JSON })
-@Description("Representation of how a workflow run's working directory tree looks.")
-public interface TavernaServerDirectoryREST {
-	/**
-	 * Get the working directory of the workflow run.
-	 * 
-	 * @param ui
-	 *            About how this method was called.
-	 * @return A description of the working directory.
-	 * @throws FilesystemAccessException
-	 */
-	@GET
-	@Path("/")
-	@Description("Describes the working directory of the workflow run.")
-	@Nonnull
-	DirectoryContents getDescription(@Nonnull @Context UriInfo ui)
-			throws FilesystemAccessException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path("{path:.*}")
-	@Description("Produces the description of the files/directories' baclava operations.")
-	Response options(@PathParam("path") List<PathSegment> path);
-
-	/**
-	 * Gets a description of the named entity in or beneath the working
-	 * directory of the workflow run, which may be either a {@link Directory} or
-	 * a {@link File}.
-	 * 
-	 * @param path
-	 *            The path to the thing to describe.
-	 * @param ui
-	 *            About how this method was called.
-	 * @param headers
-	 *            About what the caller was looking for.
-	 * @return An HTTP response containing a description of the named thing.
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the file or directory can't be looked up.
-	 * @throws FilesystemAccessException
-	 *             If something went wrong during the filesystem operation.
-	 * @throws NegotiationFailedException
-	 *             If the content type being downloaded isn't one that this
-	 *             method can support.
-	 */
-	@GET
-	@Path("{path:.+}")
-	@Produces({ XML, JSON, BYTES, ZIP, WILDCARD })
-	@Description("Gives a description of the named entity in or beneath the "
-			+ "working directory of the workflow run (either a Directory or File).")
-	@Nonnull
-	Response getDirectoryOrFileContents(
-			@Nonnull @PathParam("path") List<PathSegment> path,
-			@Nonnull @Context UriInfo ui, @Nonnull @Context HttpHeaders headers)
-			throws NoDirectoryEntryException, FilesystemAccessException,
-			NegotiationFailedException;
-
-	/**
-	 * Creates a directory in the filesystem beneath the working directory of
-	 * the workflow run, or creates or updates a file's contents, where that
-	 * file is in or below the working directory of a workflow run.
-	 * 
-	 * @param parent
-	 *            The directory to create the directory in.
-	 * @param operation
-	 *            What to call the directory to create.
-	 * @param ui
-	 *            About how this method was called.
-	 * @return An HTTP response indicating where the directory was actually made
-	 *         or what file was created/updated.
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the containing directory can't be looked up.
-	 * @throws NoUpdateException
-	 *             If the user is not permitted to update the run.
-	 * @throws FilesystemAccessException
-	 *             If something went wrong during the filesystem operation.
-	 */
-	@POST
-	@Path("{path:.*}")
-	@Description("Creates a directory in the filesystem beneath the working "
-			+ "directory of the workflow run, or creates or updates a file's "
-			+ "contents, where that file is in or below the working directory "
-			+ "of a workflow run.")
-	@Nonnull
-	Response makeDirectoryOrUpdateFile(
-			@Nonnull @PathParam("path") List<PathSegment> parent,
-			@Nonnull MakeOrUpdateDirEntry operation,
-			@Nonnull @Context UriInfo ui) throws NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Creates or updates a file in a particular location beneath the working
-	 * directory of the workflow run.
-	 * 
-	 * @param file
-	 *            The path to the file to create or update.
-	 * @param referenceList
-	 *            Location to get the file's contents from. Must be
-	 *            <i>publicly</i> readable.
-	 * @param ui
-	 *            About how this method was called.
-	 * @return An HTTP response indicating what file was created/updated.
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the containing directory can't be looked up.
-	 * @throws NoUpdateException
-	 *             If the user is not permitted to update the run.
-	 * @throws FilesystemAccessException
-	 *             If something went wrong during the filesystem operation.
-	 */
-	@POST
-	@Path("{path:(.*)}")
-	@Consumes(URI_LIST)
-	@Description("Creates or updates a file in a particular location beneath the "
-			+ "working directory of the workflow run with the contents of a "
-			+ "publicly readable URL.")
-	@Nonnull
-	Response setFileContentsFromURL(@PathParam("path") List<PathSegment> file,
-			List<URI> referenceList, @Context UriInfo ui)
-			throws NoDirectoryEntryException, NoUpdateException,
-			FilesystemAccessException;
-
-    /**
-	 * Creates or updates a file in a particular location beneath the working
-	 * directory of the workflow run.
-	 * 
-	 * @param file
-	 *            The path to the file to create or update.
-	 * @param contents
-	 *            Stream of bytes to set the file's contents to.
-	 * @param ui
-	 *            About how this method was called.
-	 * @return An HTTP response indicating what file was created/updated.
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the containing directory can't be looked up.
-	 * @throws NoUpdateException
-	 *             If the user is not permitted to update the run.
-	 * @throws FilesystemAccessException
-	 *             If something went wrong during the filesystem operation.
-	 */
-	@PUT
-	@Path("{path:(.*)}")
-	@Consumes({ BYTES, WILDCARD })
-	@Description("Creates or updates a file in a particular location beneath the "
-			+ "working directory of the workflow run.")
-	@Nonnull
-	Response setFileContents(@PathParam("path") List<PathSegment> file,
-			InputStream contents, @Context UriInfo ui)
-			throws NoDirectoryEntryException, NoUpdateException,
-			FilesystemAccessException;
-
-	/**
-	 * Deletes a file or directory that is in or below the working directory of
-	 * a workflow run.
-	 * 
-	 * @param path
-	 *            The path to the file or directory.
-	 * @return An HTTP response to the method.
-	 * @throws NoUpdateException
-	 *             If the user is not permitted to update the run.
-	 * @throws FilesystemAccessException
-	 *             If something went wrong during the filesystem operation.
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the file or directory can't be looked up.
-	 */
-	@DELETE
-	@Path("{path:.*}")
-	@Description("Deletes a file or directory that is in or below the working "
-			+ "directory of a workflow run.")
-	@Nonnull
-	Response destroyDirectoryEntry(@PathParam("path") List<PathSegment> path)
-			throws NoUpdateException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Exception thrown to indicate a failure by the client to provide an
-	 * acceptable content type.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@SuppressWarnings("serial")
-	public static class NegotiationFailedException extends Exception {
-		public List<Variant> accepted;
-
-		public NegotiationFailedException(String msg, List<Variant> accepted) {
-			super(msg);
-			this.accepted = unmodifiableList(accepted);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java
deleted file mode 100644
index 154a1eb..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.TEXT;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.TavernaServerInputREST.PathNames.BACLAVA;
-import static org.taverna.server.master.rest.TavernaServerInputREST.PathNames.EXPECTED;
-import static org.taverna.server.master.rest.TavernaServerInputREST.PathNames.ONE_INPUT;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.PathSegment;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElements;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.exceptions.BadInputPortNameException;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.port_description.InputDescription;
-
-/**
- * This represents how a Taverna Server workflow run's inputs looks to a RESTful
- * API.
- * 
- * @author Donal Fellows.
- */
-@RolesAllowed(USER)
-@Description("This represents how a Taverna Server workflow run's inputs "
-		+ "looks to a RESTful API.")
-public interface TavernaServerInputREST {
-	/**
-	 * @return A description of the various URIs to inputs associated with a
-	 *         workflow run.
-	 */
-	@GET
-	@Path("/")
-	@Produces({ XML, JSON })
-	@Description("Describe the sub-URIs of this resource.")
-	@Nonnull
-	InputsDescriptor get();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path("/")
-	@Description("Produces the description of one run's inputs' operations.")
-	Response options();
-
-	/**
-	 * @return A description of the various URIs to inputs associated with a
-	 *         workflow run.
-	 */
-	@GET
-	@Path(EXPECTED)
-	@Produces({ XML, JSON })
-	@Description("Describe the expected inputs of this workflow run.")
-	@Nonnull
-	InputDescription getExpected();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(EXPECTED)
-	@Description("Produces the description of the expected inputs' operations.")
-	Response expectedOptions();
-
-	/**
-	 * @return The Baclava file that will supply all the inputs to the workflow
-	 *         run, or empty to indicate that no such file is specified.
-	 */
-	@GET
-	@Path(BACLAVA)
-	@Produces(TEXT)
-	@Description("Gives the Baclava file describing the inputs, or empty if "
-			+ "individual files are used.")
-	@Nonnull
-	String getBaclavaFile();
-
-	/**
-	 * Set the Baclava file that will supply all the inputs to the workflow run.
-	 * 
-	 * @param filename
-	 *            The filename to set.
-	 * @return The name of the Baclava file that was actually set.
-	 * @throws NoUpdateException
-	 *             If the user can't update the run.
-	 * @throws BadStateChangeException
-	 *             If the run is not Initialized.
-	 * @throws FilesystemAccessException
-	 *             If the filename starts with a <tt>/</tt> or if it contains a
-	 *             <tt>..</tt> segment.
-	 */
-	@PUT
-	@Path(BACLAVA)
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Description("Sets the Baclava file describing the inputs.")
-	@Nonnull
-	String setBaclavaFile(@Nonnull String filename) throws NoUpdateException,
-			BadStateChangeException, FilesystemAccessException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(BACLAVA)
-	@Description("Produces the description of the inputs' baclava operations.")
-	Response baclavaOptions();
-
-	/**
-	 * Get what input is set for the specific input.
-	 * 
-	 * @param name
-	 *            The input to set.
-	 * @param uriInfo
-	 *            About the URI used to access this resource.
-	 * @return A description of the input.
-	 * @throws BadInputPortNameException
-	 *             If no input with that name exists.
-	 */
-	@GET
-	@Path(ONE_INPUT)
-	@Produces({ XML, JSON })
-	@Description("Gives a description of what is used to supply a particular "
-			+ "input.")
-	@Nonnull
-	InDesc getInput(@Nonnull @PathParam("name") String name,
-			@Context UriInfo uriInfo) throws BadInputPortNameException;
-
-	/**
-	 * Set what an input uses to provide data into the workflow run.
-	 * 
-	 * @param name
-	 *            The name of the input.
-	 * @param inputDescriptor
-	 *            A description of the input
-	 * @param uriInfo
-	 *            About the URI used to access this resource.
-	 * @return A description of the input.
-	 * @throws NoUpdateException
-	 *             If the user can't update the run.
-	 * @throws BadStateChangeException
-	 *             If the run is not Initialized.
-	 * @throws FilesystemAccessException
-	 *             If a filename is being set and the filename starts with a
-	 *             <tt>/</tt> or if it contains a <tt>..</tt> segment.
-	 * @throws BadInputPortNameException
-	 *             If no input with that name exists.
-	 * @throws BadPropertyValueException
-	 *             If some bad misconfiguration has happened.
-	 */
-	@PUT
-	@Path(ONE_INPUT)
-	@Consumes({ XML, JSON })
-	@Produces({ XML, JSON })
-	@Description("Sets the source for a particular input port.")
-	@Nonnull
-	InDesc setInput(@Nonnull @PathParam("name") String name,
-			@Nonnull InDesc inputDescriptor, @Context UriInfo uriInfo) throws NoUpdateException,
-			BadStateChangeException, FilesystemAccessException,
-			BadPropertyValueException, BadInputPortNameException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ONE_INPUT)
-	@Description("Produces the description of the one input's operations.")
-	Response inputOptions(@PathParam("name") String name);
-
-	interface PathNames {
-		final String EXPECTED = "expected";
-		final String BACLAVA = "baclava";
-		final String ONE_INPUT = "input/{name}";
-	}
-
-	/**
-	 * A description of the structure of inputs to a Taverna workflow run, done
-	 * with JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "runInputs")
-	@XmlType(name = "TavernaRunInputs")
-	public static class InputsDescriptor extends VersionedElement {
-		/**
-		 * Where to find a description of the expected inputs to this workflow
-		 * run.
-		 */
-		public Uri expected;
-		/**
-		 * Where to find the overall Baclava document filename (if set).
-		 */
-		public Uri baclava;
-		/**
-		 * Where to find the details of inputs to particular ports (if set).
-		 */
-		public List<Uri> input;
-
-		/**
-		 * Make a blank description of the inputs.
-		 */
-		public InputsDescriptor() {
-		}
-
-		/**
-		 * Make the description of the inputs.
-		 * 
-		 * @param ui
-		 *            Information about the URIs to generate.
-		 * @param run
-		 *            The run whose inputs are to be described.
-		 */
-		public InputsDescriptor(UriInfo ui, TavernaRun run) {
-			super(true);
-			expected = new Uri(ui, EXPECTED);
-			baclava = new Uri(ui, BACLAVA);
-			input = new ArrayList<>();
-			for (Input i : run.getInputs())
-				input.add(new Uri(ui, ONE_INPUT, i.getName()));
-		}
-	}
-
-	/**
-	 * The Details of a particular input port's value assignment, done with
-	 * JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "runInput")
-	@XmlType(name = "InputDescription")
-	public static class InDesc extends VersionedElement {
-		/** Make a blank description of an input port. */
-		public InDesc() {
-		}
-
-		/**
-		 * Make a description of the given input port.
-		 * 
-		 * @param inputPort
-		 */
-		public InDesc(Input inputPort, UriInfo ui) {
-			super(true);
-			name = inputPort.getName();
-			if (inputPort.getFile() != null) {
-				assignment = new InDesc.File();
-				assignment.contents = inputPort.getFile();
-			} else {
-				assignment = new InDesc.Value();
-				assignment.contents = inputPort.getValue();
-			}
-			// .../runs/{id}/input/input/{name} ->
-			// .../runs/{id}/input/expected#{name}
-			UriBuilder ub = ui.getBaseUriBuilder();
-			List<PathSegment> segments = ui.getPathSegments();
-			for (PathSegment s : segments.subList(0, segments.size() - 2))
-				ub.segment(s.getPath());
-			ub.fragment(name);
-			descriptorRef = new Uri(ub).ref;
-		}
-
-		/** The name of the port. */
-		@XmlAttribute(required = false)
-		public String name;
-		/** Where the port is described. Ignored in user input. */
-		@XmlAttribute(required = false)
-		@XmlSchemaType(name = "anyURI")
-		public URI descriptorRef;
-		/** The character to use to split the input into a list. */
-		@XmlAttribute(name = "listDelimiter", required = false)
-		public String delimiter;
-
-		/**
-		 * Either a filename or a literal string, used to provide input to a
-		 * workflow port.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "InputContents")
-		public static abstract class AbstractContents {
-			/**
-			 * The contents of the description of the input port. Meaning not
-			 * defined.
-			 */
-			@XmlValue
-			public String contents;
-		};
-
-		/**
-		 * The name of a file that provides input to the port. The
-		 * {@link AbstractContents#contents contents} field is a filename.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "")
-		public static class File extends AbstractContents {
-		}
-
-		/**
-		 * The literal input to the port. The {@link AbstractContents#contents
-		 * contents} field is a literal input value.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "")
-		public static class Value extends AbstractContents {
-		}
-
-		/**
-		 * A reference to a file elsewhere <i>on this server</i>. The
-		 * {@link AbstractContents#contents contents} field is a URL to the file
-		 * (using the RESTful notation).
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "")
-		public static class Reference extends AbstractContents {
-		}
-
-		/**
-		 * The assignment of input values to the port.
-		 */
-		@XmlElements({ @XmlElement(name = "file", type = File.class),
-				@XmlElement(name = "reference", type = Reference.class),
-				@XmlElement(name = "value", type = Value.class) })
-		public AbstractContents assignment;
-	}
-}


[29/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/StrippedDownAuthProvider.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/StrippedDownAuthProvider.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/StrippedDownAuthProvider.java
new file mode 100644
index 0000000..dc489ae
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/StrippedDownAuthProvider.java
@@ -0,0 +1,294 @@
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.security.authentication.AccountExpiredException;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.CredentialsExpiredException;
+import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.authentication.LockedException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+
+/**
+ * A stripped down version of a
+ * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider
+ * DaoAuthenticationProvider}/
+ * {@link org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider
+ * AbstractUserDetailsAuthenticationProvider} that avoids much of the overhead
+ * associated with that class.
+ */
+public class StrippedDownAuthProvider implements AuthenticationProvider {
+	/**
+	 * The plaintext password used to perform
+	 * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when
+	 * the user is not found to avoid SEC-2056.
+	 */
+	private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
+
+	/**
+	 * The password used to perform
+	 * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when
+	 * the user is not found to avoid SEC-2056. This is necessary, because some
+	 * {@link PasswordEncoder} implementations will short circuit if the
+	 * password is not in a valid format.
+	 */
+	private String userNotFoundEncodedPassword;
+	private UserDetailsService userDetailsService;
+	private PasswordEncoder passwordEncoder;
+	private Map<String, AuthCacheEntry> authCache = new HashMap<>();
+	protected final Log logger = LogFactory.getLog(getClass());
+
+	private static class AuthCacheEntry {
+		private String creds;
+		private long timestamp;
+		private static final long VALIDITY = 1000 * 60 * 20;
+		AuthCacheEntry(String credentials) {
+			creds = credentials;
+			timestamp = System.currentTimeMillis();
+		}
+		boolean valid(String password) {
+			return creds.equals(password) && timestamp+VALIDITY > System.currentTimeMillis();
+		}
+	}
+
+	@PerfLogged
+	@Override
+	public Authentication authenticate(Authentication authentication)
+			throws AuthenticationException {
+
+		if (!(authentication instanceof UsernamePasswordAuthenticationToken))
+			throw new IllegalArgumentException(
+					"can only authenticate against username+password");
+		UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
+
+		// Determine username
+		String username = (auth.getPrincipal() == null) ? "NONE_PROVIDED"
+				: auth.getName();
+
+		UserDetails user;
+
+		try {
+			user = retrieveUser(username, auth);
+			if (user == null)
+				throw new IllegalStateException(
+						"retrieveUser returned null - a violation of the interface contract");
+		} catch (UsernameNotFoundException notFound) {
+			if (logger.isDebugEnabled())
+				logger.debug("User '" + username + "' not found", notFound);
+			throw new BadCredentialsException("Bad credentials");
+		}
+
+		// Pre-auth
+		if (!user.isAccountNonLocked())
+			throw new LockedException("User account is locked");
+		if (!user.isEnabled())
+			throw new DisabledException("User account is disabled");
+		if (!user.isAccountNonExpired())
+			throw new AccountExpiredException("User account has expired");
+		Object credentials = auth.getCredentials();
+		if (credentials == null) {
+			logger.debug("Authentication failed: no credentials provided");
+
+			throw new BadCredentialsException("Bad credentials");
+		}
+
+		String providedPassword = credentials.toString();
+		boolean matched = false;
+		synchronized (authCache) {
+			AuthCacheEntry pw = authCache.get(username);
+			if (pw != null && providedPassword != null) {
+				if (pw.valid(providedPassword))
+					matched = true;
+				else
+					authCache.remove(username);
+			}
+		}
+		// Auth
+		if (!matched) {
+			if (!passwordEncoder.matches(providedPassword, user.getPassword())) {
+				logger.debug("Authentication failed: password does not match stored value");
+
+				throw new BadCredentialsException("Bad credentials");
+			}
+			if (providedPassword != null)
+				synchronized (authCache) {
+					authCache.put(username, new AuthCacheEntry(providedPassword));
+				}
+		}
+
+		// Post-auth
+		if (!user.isCredentialsNonExpired())
+			throw new CredentialsExpiredException(
+					"User credentials have expired");
+
+		return createSuccessAuthentication(user, auth, user);
+	}
+
+	@PreDestroy
+	void clearCache() {
+		authCache.clear();
+	}
+
+	/**
+	 * Creates a successful {@link Authentication} object.
+	 * <p>
+	 * Protected so subclasses can override.
+	 * </p>
+	 * <p>
+	 * Subclasses will usually store the original credentials the user supplied
+	 * (not salted or encoded passwords) in the returned
+	 * <code>Authentication</code> object.
+	 * </p>
+	 * 
+	 * @param principal
+	 *            that should be the principal in the returned object (defined
+	 *            by the {@link #isForcePrincipalAsString()} method)
+	 * @param authentication
+	 *            that was presented to the provider for validation
+	 * @param user
+	 *            that was loaded by the implementation
+	 * 
+	 * @return the successful authentication token
+	 */
+	private Authentication createSuccessAuthentication(Object principal,
+			Authentication authentication, UserDetails user) {
+		/*
+		 * Ensure we return the original credentials the user supplied, so
+		 * subsequent attempts are successful even with encoded passwords. Also
+		 * ensure we return the original getDetails(), so that future
+		 * authentication events after cache expiry contain the details
+		 */
+		UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
+				principal, authentication.getCredentials(),
+				user.getAuthorities());
+		result.setDetails(authentication.getDetails());
+
+		return result;
+	}
+
+	@Override
+	public boolean supports(Class<?> authentication) {
+		return UsernamePasswordAuthenticationToken.class
+				.isAssignableFrom(authentication);
+	}
+
+	/**
+	 * Allows subclasses to actually retrieve the <code>UserDetails</code> from
+	 * an implementation-specific location, with the option of throwing an
+	 * <code>AuthenticationException</code> immediately if the presented
+	 * credentials are incorrect (this is especially useful if it is necessary
+	 * to bind to a resource as the user in order to obtain or generate a
+	 * <code>UserDetails</code>).
+	 * <p>
+	 * Subclasses are not required to perform any caching, as the
+	 * <code>AbstractUserDetailsAuthenticationProvider</code> will by default
+	 * cache the <code>UserDetails</code>. The caching of
+	 * <code>UserDetails</code> does present additional complexity as this means
+	 * subsequent requests that rely on the cache will need to still have their
+	 * credentials validated, even if the correctness of credentials was assured
+	 * by subclasses adopting a binding-based strategy in this method.
+	 * Accordingly it is important that subclasses either disable caching (if
+	 * they want to ensure that this method is the only method that is capable
+	 * of authenticating a request, as no <code>UserDetails</code> will ever be
+	 * cached) or ensure subclasses implement
+	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
+	 * to compare the credentials of a cached <code>UserDetails</code> with
+	 * subsequent authentication requests.
+	 * </p>
+	 * <p>
+	 * Most of the time subclasses will not perform credentials inspection in
+	 * this method, instead performing it in
+	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
+	 * so that code related to credentials validation need not be duplicated
+	 * across two methods.
+	 * </p>
+	 * 
+	 * @param username
+	 *            The username to retrieve
+	 * @param authentication
+	 *            The authentication request, which subclasses <em>may</em> need
+	 *            to perform a binding-based retrieval of the
+	 *            <code>UserDetails</code>
+	 * 
+	 * @return the user information (never <code>null</code> - instead an
+	 *         exception should the thrown)
+	 * 
+	 * @throws AuthenticationException
+	 *             if the credentials could not be validated (generally a
+	 *             <code>BadCredentialsException</code>, an
+	 *             <code>AuthenticationServiceException</code> or
+	 *             <code>UsernameNotFoundException</code>)
+	 */
+	private UserDetails retrieveUser(String username,
+			UsernamePasswordAuthenticationToken authentication)
+			throws AuthenticationException {
+		try {
+			return userDetailsService.loadUserByUsername(username);
+		} catch (UsernameNotFoundException notFound) {
+			if (authentication.getCredentials() != null) {
+				String presentedPassword = authentication.getCredentials()
+						.toString();
+				passwordEncoder.matches(presentedPassword,
+						userNotFoundEncodedPassword);
+			}
+			throw notFound;
+		} catch (AuthenticationException e) {
+			throw e;
+		} catch (Exception repositoryProblem) {
+			throw new AuthenticationServiceException(
+					repositoryProblem.getMessage(), repositoryProblem);
+		}
+	}
+
+	/**
+	 * Sets the PasswordEncoder instance to be used to encode and validate
+	 * passwords.
+	 */
+	@Required
+	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+		if (passwordEncoder == null)
+			throw new IllegalArgumentException("passwordEncoder cannot be null");
+
+		this.passwordEncoder = passwordEncoder;
+		this.userNotFoundEncodedPassword = passwordEncoder
+				.encode(USER_NOT_FOUND_PASSWORD);
+	}
+
+	@Required
+	public void setUserDetailsService(UserDetailsService userDetailsService) {
+		if (userDetailsService == null)
+			throw new IllegalStateException("A UserDetailsService must be set");
+		this.userDetailsService = userDetailsService;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/User.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/User.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/User.java
new file mode 100644
index 0000000..1fdf2bf
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/User.java
@@ -0,0 +1,166 @@
+/*
+ */
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Roles.ADMIN;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.Query;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+/**
+ * The representation of a user in the database.
+ * <p>
+ * A user consists logically of a (non-ordered) tuple of items:
+ * <ul>
+ * <li>The {@linkplain #getUsername() user name},
+ * <li>The {@linkplain #getPassword() user's password} (salted, encoded),
+ * <li>Whether the user is {@linkplain #isEnabled() enabled} (i.e., able to log
+ * in),
+ * <li>Whether the user has {@linkplain #isAdmin() administrative privileges}, and
+ * <li>What {@linkplain #getLocalUsername() system (Unix) account} the user's
+ * workflows will run as; separation between different users that are mapped to
+ * the same system account is nothing like as strongly enforced.
+ * </ul>
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceCapable(schema = "USERS", table = "LIST")
+@Query(name = "users", language = "SQL", value = "SELECT id FROM USERS.LIST ORDER BY id", resultClass = String.class)
+@XmlRootElement
+@XmlType(name = "User", propOrder = {})
+@SuppressWarnings("serial")
+public class User implements UserDetails {
+	@XmlElement
+	@Persistent
+	private boolean disabled;
+	@XmlElement(name = "username", required = true)
+	@Persistent(primaryKey = "true")
+	private String id;
+	@XmlElement(name = "password", required = true)
+	@Persistent(column = "password")
+	private String encodedPassword;
+	@XmlElement
+	@Persistent
+	private boolean admin;
+	@XmlElement
+	@Persistent
+	private String localUsername;
+
+	@Override
+	public Collection<GrantedAuthority> getAuthorities() {
+		List<GrantedAuthority> auths = new ArrayList<>();
+		auths.add(new LiteralGrantedAuthority(USER));
+		if (admin)
+			auths.add(new LiteralGrantedAuthority(ADMIN));
+		if (localUsername != null)
+			auths.add(new LiteralGrantedAuthority(AUTHORITY_PREFIX
+					+ localUsername));
+		return auths;
+	}
+
+	@Override
+	public String getPassword() {
+		return encodedPassword;
+	}
+
+	@Override
+	public String getUsername() {
+		return id;
+	}
+
+	@Override
+	public boolean isAccountNonExpired() {
+		return true;
+	}
+
+	@Override
+	public boolean isAccountNonLocked() {
+		return true;
+	}
+
+	@Override
+	public boolean isCredentialsNonExpired() {
+		return true;
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return !disabled;
+	}
+
+	void setDisabled(boolean disabled) {
+		this.disabled = disabled;
+	}
+
+	void setUsername(String username) {
+		this.id = username;
+	}
+
+	void setEncodedPassword(String password) {
+		this.encodedPassword = password;
+	}
+
+	void setAdmin(boolean admin) {
+		this.admin = admin;
+	}
+
+	public boolean isAdmin() {
+		return admin;
+	}
+
+	void setLocalUsername(String localUsername) {
+		this.localUsername = localUsername;
+	}
+
+	public String getLocalUsername() {
+		return localUsername;
+	}
+}
+
+@SuppressWarnings("serial")
+class LiteralGrantedAuthority implements GrantedAuthority {
+	private String auth;
+
+	LiteralGrantedAuthority(String auth) {
+		this.auth = auth;
+	}
+
+	@Override
+	public String getAuthority() {
+		return auth;
+	}
+
+	@Override
+	public String toString() {
+		return "AUTHORITY(" + auth + ")";
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStore.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStore.java
new file mode 100644
index 0000000..3177d5c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStore.java
@@ -0,0 +1,402 @@
+/*
+ */
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */
+
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.taverna.server.master.common.Roles.ADMIN;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.jdo.annotations.PersistenceAware;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedOperation;
+import org.springframework.jmx.export.annotation.ManagedOperationParameter;
+import org.springframework.jmx.export.annotation.ManagedOperationParameters;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.core.userdetails.memory.UserAttribute;
+import org.springframework.security.core.userdetails.memory.UserAttributeEditor;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.JDOSupport;
+
+/**
+ * The bean class that is responsible for managing the users in the database.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceAware
+@ManagedResource(objectName = JMX_ROOT + "Users", description = "The user database.")
+public class UserStore extends JDOSupport<User> implements UserDetailsService,
+		UserStoreAPI {
+	/** The logger for the user store. */
+	private transient Log log = getLog("Taverna.Server.UserDB");
+
+	public UserStore() {
+		super(User.class);
+	}
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	private Map<String, BootstrapUserInfo> base = new HashMap<>();
+	private String defLocalUser;
+	private PasswordEncoder encoder;
+	private volatile int epoch;
+
+	/**
+	 * Install the encoder that will be used to turn a plaintext password into
+	 * something that it is safe to store in the database.
+	 * 
+	 * @param encoder
+	 *            The password encoder bean to install.
+	 */
+	public void setEncoder(PasswordEncoder encoder) {
+		this.encoder = encoder;
+	}
+
+	public void setBaselineUserProperties(Properties props) {
+		UserAttributeEditor parser = new UserAttributeEditor();
+
+		for (Object name : props.keySet()) {
+			String username = (String) name;
+			String value = props.getProperty(username);
+
+			// Convert value to a password, enabled setting, and list of granted
+			// authorities
+			parser.setAsText(value);
+
+			UserAttribute attr = (UserAttribute) parser.getValue();
+			if (attr != null && attr.isEnabled())
+				base.put(username, new BootstrapUserInfo(username, attr));
+		}
+	}
+
+	private void installPassword(User u, String password) {
+		u.setEncodedPassword(encoder.encode(password));
+	}
+
+	public void setDefaultLocalUser(String defLocalUser) {
+		this.defLocalUser = defLocalUser;
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> getUsers() {
+		return (List<String>) namedQuery("users").execute();
+	}
+
+	@WithinSingleTransaction
+	@PostConstruct
+	void initDB() {
+		if (base == null || base.isEmpty())
+			log.warn("no baseline user collection");
+		else if (!getUsers().isEmpty())
+			log.info("using existing users from database");
+		else
+			for (String username : base.keySet()) {
+				BootstrapUserInfo ud = base.get(username);
+				if (ud == null)
+					continue;
+				User u = ud.get(encoder);
+				if (u == null)
+					continue;
+				log.info("bootstrapping user " + username + " in the database");
+				persist(u);
+			}
+		base = null;
+		epoch++;
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedAttribute(description = "The list of server accounts known about.", currencyTimeLimit = 30)
+	public List<String> getUserNames() {
+		return getUsers();
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	public User getUser(String userName) {
+		return detach(getById(userName));
+	}
+
+	/**
+	 * Get information about a server account.
+	 * 
+	 * @param userName
+	 *            The username to look up.
+	 * @return A description map intended for use by a server admin over JMX.
+	 */
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Get information about a server account.")
+	@ManagedOperationParameters(@ManagedOperationParameter(name = "userName", description = "The username to look up."))
+	public Map<String, String> getUserInfo(String userName) {
+		User u = getById(userName);
+		Map<String, String> info = new HashMap<>();
+		info.put("name", u.getUsername());
+		info.put("admin", u.isAdmin() ? "yes" : "no");
+		info.put("enabled", u.isEnabled() ? "yes" : "no");
+		info.put("localID", u.getLocalUsername());
+		return info;
+	}
+
+	/**
+	 * Get a list of all the users in the database.
+	 * 
+	 * @return A list of user details, <i>copied</i> out of the database.
+	 */
+	@PerfLogged
+	@WithinSingleTransaction
+	public List<UserDetails> listUsers() {
+		ArrayList<UserDetails> result = new ArrayList<>();
+		for (String id : getUsers())
+			result.add(detach(getById(id)));
+		return result;
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Create a new user account; the account will be disabled and "
+			+ "non-administrative by default. Does not create any underlying system account.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to create."),
+			@ManagedOperationParameter(name = "password", description = "The password to use."),
+			@ManagedOperationParameter(name = "coupleLocalUsername", description = "Whether to set the local user name to the 'main' one.") })
+	public void addUser(String username, String password,
+			boolean coupleLocalUsername) {
+		if (username.matches(".*[^a-zA-Z0-9].*"))
+			throw new IllegalArgumentException(
+					"bad user name; must be pure alphanumeric");
+		if (getById(username) != null)
+			throw new IllegalArgumentException("user name already exists");
+		User u = new User();
+		u.setDisabled(true);
+		u.setAdmin(false);
+		u.setUsername(username);
+		installPassword(u, password);
+		if (coupleLocalUsername)
+			u.setLocalUsername(username);
+		else
+			u.setLocalUsername(defLocalUser);
+		log.info("creating user for " + username);
+		persist(u);
+		epoch++;
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Set or clear whether this account is enabled. "
+			+ "Disabled accounts cannot be used to log in.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
+			@ManagedOperationParameter(name = "enabled", description = "Whether to enable the account.") })
+	public void setUserEnabled(String username, boolean enabled) {
+		User u = getById(username);
+		if (u != null) {
+			u.setDisabled(!enabled);
+			log.info((enabled ? "enabling" : "disabling") + " user " + username);
+			epoch++;
+		}
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Set or clear the mark on an account that indicates "
+			+ "that it has administrative privileges.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
+			@ManagedOperationParameter(name = "admin", description = "Whether the account has admin privileges.") })
+	public void setUserAdmin(String username, boolean admin) {
+		User u = getById(username);
+		if (u != null) {
+			u.setAdmin(admin);
+			log.info((admin ? "enabling" : "disabling") + " user " + username
+					+ " admin status");
+			epoch++;
+		}
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Change the password for an account.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
+			@ManagedOperationParameter(name = "password", description = "The new password to use.") })
+	public void setUserPassword(String username, String password) {
+		User u = getById(username);
+		if (u != null) {
+			installPassword(u, password);
+			log.info("changing password for user " + username);
+			epoch++;
+		}
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Change what local system account to use for a server account.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
+			@ManagedOperationParameter(name = "password", description = "The new local user account use.") })
+	public void setUserLocalUser(String username, String localUsername) {
+		User u = getById(username);
+		if (u != null) {
+			u.setLocalUsername(localUsername);
+			log.info("mapping user " + username + " to local account "
+					+ localUsername);
+			epoch++;
+		}
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Delete a server account. The underlying "
+			+ "system account is not modified.")
+	@ManagedOperationParameters(@ManagedOperationParameter(name = "username", description = "The username to delete."))
+	public void deleteUser(String username) {
+		delete(getById(username));
+		log.info("deleting user " + username);
+		epoch++;
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	public UserDetails loadUserByUsername(String username)
+			throws UsernameNotFoundException, DataAccessException {
+		User u;
+		if (base != null) {
+			log.warn("bootstrap user store still installed!");
+			BootstrapUserInfo ud = base.get(username);
+			if (ud != null) {
+				log.warn("retrieved production credentials for " + username
+						+ " from bootstrap store");
+				u = ud.get(encoder);
+				if (u != null)
+					return u;
+			}
+		}
+		try {
+			u = detach(getById(username));
+		} catch (NullPointerException npe) {
+			throw new UsernameNotFoundException("who are you?");
+		} catch (Exception ex) {
+			throw new UsernameNotFoundException("who are you?", ex);
+		}
+		if (u != null)
+			return u;
+		throw new UsernameNotFoundException("who are you?");
+	}
+
+	int getEpoch() {
+		return epoch;
+	}
+
+	public static class CachedUserStore implements UserDetailsService {
+		private int epoch;
+		private Map<String, UserDetails> cache = new HashMap<>();
+		private UserStore realStore;
+
+		@Required
+		public void setRealStore(UserStore store) {
+			this.realStore = store;
+		}
+
+		@Override
+		@PerfLogged
+		public UserDetails loadUserByUsername(String username) {
+			int epoch = realStore.getEpoch();
+			UserDetails details;
+			synchronized (cache) {
+				if (epoch != this.epoch) {
+					cache.clear();
+					this.epoch = epoch;
+					details = null;
+				} else
+					details = cache.get(username);
+			}
+			if (details == null) {
+				details = realStore.loadUserByUsername(username);
+				synchronized (cache) {
+					cache.put(username, details);
+				}
+			}
+			return details;
+		}
+	}
+
+	private static class BootstrapUserInfo {
+		private String user;
+		private String pass;
+		private Collection<GrantedAuthority> auth;
+
+		BootstrapUserInfo(String username, UserAttribute attr) {
+			user = username;
+			pass = attr.getPassword();
+			auth = attr.getAuthorities();
+		}
+
+		User get(PasswordEncoder encoder) {
+			User u = new User();
+			boolean realUser = false;
+			for (GrantedAuthority ga : auth) {
+				String a = ga.getAuthority();
+				if (a.startsWith(AUTHORITY_PREFIX))
+					u.setLocalUsername(a.substring(AUTHORITY_PREFIX.length()));
+				else if (a.equals(USER))
+					realUser = true;
+				else if (a.equals(ADMIN))
+					u.setAdmin(true);
+			}
+			if (!realUser)
+				return null;
+			u.setUsername(user);
+			u.setEncodedPassword(encoder.encode(pass));
+			u.setDisabled(false);
+			return u;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStoreAPI.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStoreAPI.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStoreAPI.java
new file mode 100644
index 0000000..c4caf3c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/UserStoreAPI.java
@@ -0,0 +1,107 @@
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+/**
+ * The API that is exposed by the DAO that exposes user management.
+ * 
+ * @author Donal Fellows
+ * @see User
+ */
+public interface UserStoreAPI {
+	/**
+	 * List the currently-known account names.
+	 * 
+	 * @return A list of users in the database. Note that this is a snapshot.
+	 */
+	List<String> getUserNames();
+
+	/**
+	 * Get a particular user's description.
+	 * 
+	 * @param userName
+	 *            The username to look up.
+	 * @return A <i>copy</i> of the user description.
+	 */
+	User getUser(String userName);
+
+	/**
+	 * Create a new user account; the account will be disabled and
+	 * non-administrative by default. Does not create any underlying system
+	 * account.
+	 * 
+	 * @param username
+	 *            The username to create.
+	 * @param password
+	 *            The password to use.
+	 * @param coupleLocalUsername
+	 *            Whether to set the local user name to the 'main' one.
+	 */
+	void addUser(String username, String password, boolean coupleLocalUsername);
+
+	/**
+	 * Set or clear whether this account is enabled. Disabled accounts cannot be
+	 * used to log in.
+	 * 
+	 * @param username
+	 *            The username to adjust.
+	 * @param enabled
+	 *            Whether to enable the account.
+	 */
+	void setUserEnabled(String username, boolean enabled);
+
+	/**
+	 * Set or clear the mark on an account that indicates that it has
+	 * administrative privileges.
+	 * 
+	 * @param username
+	 *            The username to adjust.
+	 * @param admin
+	 *            Whether the account has admin privileges.
+	 */
+	void setUserAdmin(String username, boolean admin);
+
+	/**
+	 * Change the password for an account.
+	 * 
+	 * @param username
+	 *            The username to adjust.
+	 * @param password
+	 *            The new password to use.
+	 */
+	void setUserPassword(String username, String password);
+
+	/**
+	 * Change what local system account to use for a server account.
+	 * 
+	 * @param username
+	 *            The username to adjust.
+	 * @param localUsername
+	 *            The new local user account use.
+	 */
+	void setUserLocalUser(String username, String localUsername);
+
+	/**
+	 * Delete a server account. The underlying system account is not modified.
+	 * 
+	 * @param username
+	 *            The username to delete.
+	 */
+	void deleteUser(String username);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/WorkflowInternalAuthProvider.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/WorkflowInternalAuthProvider.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/WorkflowInternalAuthProvider.java
new file mode 100644
index 0000000..c733d89
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/WorkflowInternalAuthProvider.java
@@ -0,0 +1,317 @@
+/*
+ */
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */
+
+import static java.util.Collections.synchronizedMap;
+import static org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes;
+import static org.taverna.server.master.common.Roles.SELF;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.web.authentication.WebAuthenticationDetails;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.interfaces.RunStore;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.UsernamePrincipal;
+import org.taverna.server.master.worker.RunDatabaseDAO;
+
+/**
+ * A special authentication provider that allows a workflow to authenticate to
+ * itself. This is used to allow the workflow to publish to its own interaction
+ * feed.
+ * 
+ * @author Donal Fellows
+ */
+public class WorkflowInternalAuthProvider extends
+		AbstractUserDetailsAuthenticationProvider {
+	private Log log = LogFactory.getLog("Taverna.Server.UserDB");
+	private static final boolean logDecisions = true;
+	public static final String PREFIX = "wfrun_";
+	private RunDatabaseDAO dao;
+	private Map<String, String> cache;
+
+	@Required
+	public void setDao(RunDatabaseDAO dao) {
+		this.dao = dao;
+	}
+
+	@Required
+	@SuppressWarnings("serial")
+	public void setCacheBound(final int bound) {
+		cache = synchronizedMap(new LinkedHashMap<String, String>() {
+			@Override
+			protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
+				return size() > bound;
+			}
+		});
+	}
+
+	public void setAuthorizedAddresses(String[] addresses) {
+		authorizedAddresses = new HashSet<>(localAddresses);
+		for (String s : addresses)
+			authorizedAddresses.add(s);
+	}
+
+	@PostConstruct
+	public void logConfig() {
+		log.info("authorized addresses for automatic access: "
+				+ authorizedAddresses);
+	}
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	private final Set<String> localAddresses = new HashSet<>();
+	private Set<String> authorizedAddresses;
+	{
+		localAddresses.add("127.0.0.1"); // IPv4
+		localAddresses.add("::1"); // IPv6
+		try {
+			InetAddress addr = InetAddress.getLocalHost();
+			if (!addr.isLoopbackAddress())
+				localAddresses.add(addr.getHostAddress());
+		} catch (UnknownHostException e) {
+			// Ignore the exception
+		}
+		authorizedAddresses = new HashSet<>(localAddresses);
+	}
+
+	/**
+	 * Check that the authentication request is actually valid for the given
+	 * user record.
+	 * 
+	 * @param userRecord
+	 *            as retrieved from the
+	 *            {@link #retrieveUser(String, UsernamePasswordAuthenticationToken)}
+	 *            or <code>UserCache</code>
+	 * @param principal
+	 *            the principal that is trying to authenticate (and that we're
+	 *            trying to bind)
+	 * @param credentials
+	 *            the credentials (e.g., password) presented by the principal
+	 * 
+	 * @throws AuthenticationException
+	 *             AuthenticationException if the credentials could not be
+	 *             validated (generally a <code>BadCredentialsException</code>,
+	 *             an <code>AuthenticationServiceException</code>)
+	 * @throws Exception
+	 *             If something goes wrong. Will be logged and converted to a
+	 *             generic AuthenticationException.
+	 */
+	protected void additionalAuthenticationChecks(UserDetails userRecord,
+			@Nonnull Object principal, @Nonnull Object credentials)
+			throws Exception {
+		@Nonnull
+		HttpServletRequest req = ((ServletRequestAttributes) currentRequestAttributes())
+				.getRequest();
+
+		// Are we coming from a "local" address?
+		if (!req.getLocalAddr().equals(req.getRemoteAddr())
+				&& !authorizedAddresses.contains(req.getRemoteAddr())) {
+			if (logDecisions)
+				log.info("attempt to use workflow magic token from untrusted address:"
+						+ " token="
+						+ userRecord.getUsername()
+						+ ", address="
+						+ req.getRemoteAddr());
+			throw new BadCredentialsException("bad login token");
+		}
+
+		// Does the password match?
+		if (!credentials.equals(userRecord.getPassword())) {
+			if (logDecisions)
+				log.info("workflow magic token is untrusted due to password mismatch:"
+						+ " wanted="
+						+ userRecord.getPassword()
+						+ ", got="
+						+ credentials);
+			throw new BadCredentialsException("bad login token");
+		}
+
+		if (logDecisions)
+			log.info("granted role " + SELF + " to user "
+					+ userRecord.getUsername());
+	}
+
+	/**
+	 * Retrieve the <code>UserDetails</code> from the relevant store, with the
+	 * option of throwing an <code>AuthenticationException</code> immediately if
+	 * the presented credentials are incorrect (this is especially useful if it
+	 * is necessary to bind to a resource as the user in order to obtain or
+	 * generate a <code>UserDetails</code>).
+	 * 
+	 * @param username
+	 *            The username to retrieve
+	 * @param details
+	 *            The details from the authentication request.
+	 * @see #retrieveUser(String,UsernamePasswordAuthenticationToken)
+	 * @return the user information (never <code>null</code> - instead an
+	 *         exception should the thrown)
+	 * @throws AuthenticationException
+	 *             if the credentials could not be validated (generally a
+	 *             <code>BadCredentialsException</code>, an
+	 *             <code>AuthenticationServiceException</code> or
+	 *             <code>UsernameNotFoundException</code>)
+	 * @throws Exception
+	 *             If something goes wrong. It will be logged and converted into
+	 *             a general AuthenticationException.
+	 */
+	@Nonnull
+	protected UserDetails retrieveUser(String username, Object details)
+			throws Exception {
+		if (details == null || !(details instanceof WebAuthenticationDetails))
+			throw new UsernameNotFoundException("context unsupported");
+		if (!username.startsWith(PREFIX))
+			throw new UsernameNotFoundException(
+					"unsupported username for this provider");
+		if (logDecisions)
+			log.info("request for auth for user " + username);
+		String wfid = username.substring(PREFIX.length());
+		String securityToken;
+		try {
+			securityToken = cache.get(wfid);
+			if (securityToken == null) {
+				securityToken = dao.getSecurityToken(wfid);
+				if (securityToken == null)
+					throw new UsernameNotFoundException("no such user");
+				cache.put(wfid, securityToken);
+			}
+		} catch (NullPointerException npe) {
+			throw new UsernameNotFoundException("no such user");
+		}
+		return new User(username, securityToken, true, true, true, true,
+				Arrays.asList(new LiteralGrantedAuthority(SELF),
+						new WorkflowSelfAuthority(wfid)));
+	}
+
+	@Override
+	@PerfLogged
+	protected final void additionalAuthenticationChecks(UserDetails userRecord,
+			UsernamePasswordAuthenticationToken token) {
+		try {
+			additionalAuthenticationChecks(userRecord, token.getPrincipal(),
+					token.getCredentials());
+		} catch (AuthenticationException e) {
+			throw e;
+		} catch (Exception e) {
+			log.warn("unexpected failure in authentication", e);
+			throw new AuthenticationServiceException(
+					"unexpected failure in authentication", e);
+		}
+	}
+
+	@Override
+	@Nonnull
+	@PerfLogged
+	protected final UserDetails retrieveUser(String username,
+			UsernamePasswordAuthenticationToken token) {
+		try {
+			return retrieveUser(username, token.getDetails());
+		} catch (AuthenticationException e) {
+			throw e;
+		} catch (Exception e) {
+			log.warn("unexpected failure in authentication", e);
+			throw new AuthenticationServiceException(
+					"unexpected failure in authentication", e);
+		}
+	}
+
+	@SuppressWarnings("serial")
+	public static class WorkflowSelfAuthority extends LiteralGrantedAuthority {
+		public WorkflowSelfAuthority(String wfid) {
+			super(wfid);
+		}
+
+		public String getWorkflowID() {
+			return getAuthority();
+		}
+
+		@Override
+		public String toString() {
+			return "WORKFLOW(" + getAuthority() + ")";
+		}
+	}
+
+	public static class WorkflowSelfIDMapper implements LocalIdentityMapper {
+		private Log log = LogFactory.getLog("Taverna.Server.UserDB");
+		private RunStore runStore;
+
+		@PreDestroy
+		void closeLog() {
+			log = null;
+		}
+
+		@Required
+		public void setRunStore(RunStore runStore) {
+			this.runStore = runStore;
+		}
+
+		private String getUsernameForSelfAccess(WorkflowSelfAuthority authority)
+				throws UnknownRunException {
+			return runStore.getRun(authority.getWorkflowID())
+					.getSecurityContext().getOwner().getName();
+		}
+
+		@Override
+		@PerfLogged
+		public String getUsernameForPrincipal(UsernamePrincipal user) {
+			Authentication auth = SecurityContextHolder.getContext()
+					.getAuthentication();
+			if (auth == null || !auth.isAuthenticated())
+				return null;
+			try {
+				for (GrantedAuthority authority : auth.getAuthorities())
+					if (authority instanceof WorkflowSelfAuthority)
+						return getUsernameForSelfAccess((WorkflowSelfAuthority) authority);
+			} catch (UnknownRunException e) {
+				log.warn("workflow run disappeared during computation of workflow map identity");
+			}
+			return null;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/package-info.java
new file mode 100644
index 0000000..14ad7db
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/identity/package-info.java
@@ -0,0 +1,23 @@
+/*
+ */
+/**
+ * Implementations of beans that map global user identities to local
+ * usernames.
+ */
+package org.taverna.server.master.identity;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/InteractionFeedSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/InteractionFeedSupport.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/InteractionFeedSupport.java
new file mode 100644
index 0000000..4b297dc
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/InteractionFeedSupport.java
@@ -0,0 +1,329 @@
+/*
+ */
+package org.taverna.server.master.interaction;
+/*
+ * 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.
+ */
+
+import static java.lang.management.ManagementFactory.getPlatformMBeanServer;
+import static java.util.Collections.reverse;
+import static javax.management.Query.attr;
+import static javax.management.Query.match;
+import static javax.management.Query.value;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.Nullable;
+import javax.annotation.PostConstruct;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.writer.Writer;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.TavernaServerSupport;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.utils.FilenameUtils;
+
+/**
+ * Bean that supports interaction feeds. This glues together the Abdera
+ * serialization engine and the directory-based model used inside the server.
+ * 
+ * @author Donal Fellows
+ */
+public class InteractionFeedSupport {
+	/**
+	 * The name of the resource within the run resource that is the run's
+	 * interaction feed resource.
+	 */
+	public static final String FEED_URL_DIR = "interaction";
+	/**
+	 * The name of the directory below the run working directory that will
+	 * contain the entries of the interaction feed.
+	 */
+	public static final String FEED_DIR = "feed";
+	/**
+	 * Should the contents of the entry be stripped when describing the overall
+	 * feed? This makes sense if (and only if) large entries are being pushed
+	 * through the feed.
+	 */
+	private static final boolean STRIP_CONTENTS = false;
+	/** Maximum size of an entry before truncation. */
+	private static final long MAX_ENTRY_SIZE = 50 * 1024;
+	/** Extension for entry files. */
+	private static final String EXT = ".atom";
+
+	private TavernaServerSupport support;
+	private FilenameUtils utils;
+	private Writer writer;
+	private Parser parser;
+	private Factory factory;
+	private UriBuilderFactory uriBuilder;
+
+	private AtomicInteger counter = new AtomicInteger();
+
+	@Required
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Required
+	public void setUtils(FilenameUtils utils) {
+		this.utils = utils;
+	}
+
+	@Required
+	public void setAbdera(Abdera abdera) {
+		this.factory = abdera.getFactory();
+		this.parser = abdera.getParser();
+		this.writer = abdera.getWriterFactory().getWriter("prettyxml");
+	}
+
+	@Required
+	// webapp
+	public void setUriBuilder(UriBuilderFactory uriBuilder) {
+		this.uriBuilder = uriBuilder;
+	}
+
+	private final Map<String, URL> endPoints = new HashMap<>();
+
+	@PostConstruct
+	void determinePorts() {
+		try {
+			MBeanServer mbs = getPlatformMBeanServer();
+			for (ObjectName obj : mbs.queryNames(new ObjectName(
+					"*:type=Connector,*"),
+					match(attr("protocol"), value("HTTP/1.1")))) {
+				String scheme = mbs.getAttribute(obj, "scheme").toString();
+				String port = obj.getKeyProperty("port");
+				endPoints.put(scheme, new URL(scheme + "://localhost:" + port));
+			}
+			getLog(getClass()).info(
+					"installed feed port publication mapping for "
+							+ endPoints.keySet());
+		} catch (Exception e) {
+			getLog(getClass()).error(
+					"failure in determining local port mapping", e);
+		}
+	}
+	
+	/**
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @return The URI of the feed
+	 */
+	public URI getFeedURI(TavernaRun run) {
+		return uriBuilder.getRunUriBuilder(run).path(FEED_URL_DIR).build();
+	}
+
+	@Nullable
+	public URL getLocalFeedBase(URI feedURI) {
+		if (feedURI == null)
+			return null;
+		return endPoints.get(feedURI.getScheme());
+	}
+
+	/**
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @param id
+	 *            The ID of the entry.
+	 * @return The URI of the entry.
+	 */
+	public URI getEntryURI(TavernaRun run, String id) {
+		return uriBuilder.getRunUriBuilder(run)
+				.path(FEED_URL_DIR + "/{entryID}").build(id);
+	}
+
+	private Entry getEntryFromFile(File f) throws FilesystemAccessException {
+		long size = f.getSize();
+		if (size > MAX_ENTRY_SIZE)
+			throw new FilesystemAccessException("entry larger than 50kB");
+		byte[] contents = f.getContents(0, (int) size);
+		Document<Entry> doc = parser.parse(new ByteArrayInputStream(contents));
+		return doc.getRoot();
+	}
+
+	private void putEntryInFile(Directory dir, String name, Entry contents)
+			throws FilesystemAccessException, NoUpdateException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		try {
+			writer.writeTo(contents, baos);
+		} catch (IOException e) {
+			throw new NoUpdateException("failed to serialize the ATOM entry", e);
+		}
+		File f = dir.makeEmptyFile(support.getPrincipal(), name);
+		f.appendContents(baos.toByteArray());
+	}
+
+	private List<DirectoryEntry> listPossibleEntries(TavernaRun run)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		List<DirectoryEntry> entries = new ArrayList<>(utils.getDirectory(run,
+				FEED_DIR).getContentsByDate());
+		reverse(entries);
+		return entries;
+	}
+
+	private String getRunURL(TavernaRun run) {
+		return new IRI(uriBuilder.getRunUriBuilder(run).build()).toString();
+	}
+
+	/**
+	 * Get the interaction feed for a partciular run.
+	 * 
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @return The Abdera feed descriptor.
+	 * @throws FilesystemAccessException
+	 *             If the feed directory can't be read for some reason.
+	 * @throws NoDirectoryEntryException
+	 *             If the feed directory doesn't exist or an entry is
+	 *             unexpectedly removed.
+	 */
+	public Feed getRunFeed(TavernaRun run) throws FilesystemAccessException,
+			NoDirectoryEntryException {
+		URI feedURI = getFeedURI(run);
+		Feed feed = factory.newFeed();
+		feed.setTitle("Interactions for Taverna Run \"" + run.getName() + "\"");
+		feed.addLink(new IRI(feedURI).toString(), "self");
+		feed.addLink(getRunURL(run), "workflowrun");
+		boolean fetchedDate = false;
+		for (DirectoryEntry de : listPossibleEntries(run)) {
+			if (!(de instanceof File))
+				continue;
+			try {
+				Entry e = getEntryFromFile((File) de);
+				if (STRIP_CONTENTS)
+					e.setContentElement(null);
+				feed.addEntry(e);
+				if (fetchedDate)
+					continue;
+				Date last = e.getUpdated();
+				if (last == null)
+					last = e.getPublished();
+				if (last == null)
+					last = de.getModificationDate();
+				feed.setUpdated(last);
+				fetchedDate = true;
+			} catch (FilesystemAccessException e) {
+				// Can't do anything about it, so we'll just drop the entry.
+			}
+		}
+		return feed;
+	}
+
+	/**
+	 * Gets the contents of a particular feed entry.
+	 * 
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @param entryID
+	 *            The identifier (from the path) of the entry to read.
+	 * @return The description of the entry.
+	 * @throws FilesystemAccessException
+	 *             If the entry can't be read or is too large.
+	 * @throws NoDirectoryEntryException
+	 *             If the entry can't be found.
+	 */
+	public Entry getRunFeedEntry(TavernaRun run, String entryID)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		File entryFile = utils.getFile(run, FEED_DIR + "/" + entryID + EXT);
+		return getEntryFromFile(entryFile);
+	}
+
+	/**
+	 * Given a partial feed entry, store a complete feed entry in the filesystem
+	 * for a particular run. Note that this does not permit update of an
+	 * existing entry; the entry is always created new.
+	 * 
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @param entry
+	 *            The partial entry to store
+	 * @return A link to the entry.
+	 * @throws FilesystemAccessException
+	 *             If the entry can't be stored.
+	 * @throws NoDirectoryEntryException
+	 *             If the run is improperly configured.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to do the write.
+	 * @throws MalformedURLException
+	 *             If a generated URL is illegal (shouldn't happen).
+	 */
+	public Entry addRunFeedEntry(TavernaRun run, Entry entry)
+			throws FilesystemAccessException, NoDirectoryEntryException,
+			NoUpdateException {
+		support.permitUpdate(run);
+		Date now = new Date();
+		entry.newId();
+		String localId = "entry_" + counter.incrementAndGet();
+		IRI selfLink = new IRI(getEntryURI(run, localId));
+		entry.addLink(selfLink.toString(), "self");
+		entry.addLink(getRunURL(run), "workflowrun");
+		entry.setUpdated(now);
+		entry.setPublished(now);
+		putEntryInFile(utils.getDirectory(run, FEED_DIR), localId + EXT, entry);
+		return getEntryFromFile(utils.getFile(run, FEED_DIR + "/" + localId
+				+ EXT));
+	}
+
+	/**
+	 * Deletes an entry from a feed.
+	 * 
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @param entryID
+	 *            The ID of the entry to delete.
+	 * @throws FilesystemAccessException
+	 *             If the entry can't be deleted
+	 * @throws NoDirectoryEntryException
+	 *             If the entry can't be found.
+	 * @throws NoUpdateException
+	 *             If the current user is not permitted to modify the run's
+	 *             characteristics.
+	 */
+	public void removeRunFeedEntry(TavernaRun run, String entryID)
+			throws FilesystemAccessException, NoDirectoryEntryException,
+			NoUpdateException {
+		support.permitUpdate(run);
+		utils.getFile(run, FEED_DIR + "/" + entryID + EXT).destroy();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/package-info.java
new file mode 100644
index 0000000..54ec630
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interaction/package-info.java
@@ -0,0 +1,23 @@
+/*
+ */
+/**
+ * This package contains the Atom feed implementation for interactions for a particular workflow run.
+ * @author Donal Fellows
+ */
+package org.taverna.server.master.interaction;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Directory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Directory.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Directory.java
new file mode 100644
index 0000000..bb74f5a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Directory.java
@@ -0,0 +1,95 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import java.io.PipedInputStream;
+import java.security.Principal;
+import java.util.Collection;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+/**
+ * Represents a directory that is the working directory of a workflow run, or a
+ * sub-directory of it.
+ * 
+ * @author Donal Fellows
+ * @see File
+ */
+public interface Directory extends DirectoryEntry {
+	/**
+	 * @return A list of the contents of the directory.
+	 * @throws FilesystemAccessException
+	 *             If things go wrong.
+	 */
+	Collection<DirectoryEntry> getContents() throws FilesystemAccessException;
+
+	/**
+	 * @return A list of the contents of the directory, in guaranteed date
+	 *         order.
+	 * @throws FilesystemAccessException
+	 *             If things go wrong.
+	 */
+	Collection<DirectoryEntry> getContentsByDate()
+			throws FilesystemAccessException;
+
+	/**
+	 * @return The contents of the directory (and its sub-directories) as a zip.
+	 * @throws FilesystemAccessException
+	 *             If things go wrong.
+	 */
+	ZipStream getContentsAsZip() throws FilesystemAccessException;
+
+	/**
+	 * Creates a sub-directory of this directory.
+	 * 
+	 * @param actor
+	 *            Who this is being created by.
+	 * @param name
+	 *            The name of the sub-directory.
+	 * @return A handle to the newly-created directory.
+	 * @throws FilesystemAccessException
+	 *             If the name is the same as some existing entry in the
+	 *             directory, or if something else goes wrong during creation.
+	 */
+	Directory makeSubdirectory(Principal actor, String name)
+			throws FilesystemAccessException;
+
+	/**
+	 * Creates an empty file in this directory.
+	 * 
+	 * @param actor
+	 *            Who this is being created by.
+	 * @param name
+	 *            The name of the file to create.
+	 * @return A handle to the newly-created file.
+	 * @throws FilesystemAccessException
+	 *             If the name is the same as some existing entry in the
+	 *             directory, or if something else goes wrong during creation.
+	 */
+	File makeEmptyFile(Principal actor, String name)
+			throws FilesystemAccessException;
+
+	/**
+	 * A simple pipe that produces the zipped contents of a directory.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public static class ZipStream extends PipedInputStream {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/DirectoryEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/DirectoryEntry.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/DirectoryEntry.java
new file mode 100644
index 0000000..e1a0865
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/DirectoryEntry.java
@@ -0,0 +1,60 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import java.util.Date;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+/**
+ * An entry in a {@link Directory} representing a file or sub-directory.
+ * 
+ * @author Donal Fellows
+ * @see Directory
+ * @see File
+ */
+public interface DirectoryEntry extends Comparable<DirectoryEntry> {
+	/**
+	 * @return The "local" name of the entry. This will never be "<tt>..</tt>"
+	 *         or contain the character "<tt>/</tt>".
+	 */
+	public String getName();
+
+	/**
+	 * @return The "full" name of the entry. This is computed relative to the
+	 *         workflow run's working directory. It may contain the "<tt>/</tt>"
+	 *         character.
+	 */
+	public String getFullName();
+
+	/**
+	 * @return The time that the entry was last modified.
+	 */
+	public Date getModificationDate();
+
+	/**
+	 * Destroy this directory entry, deleting the file or sub-directory. The
+	 * workflow run's working directory can never be manually destroyed.
+	 * 
+	 * @throws FilesystemAccessException
+	 *             If the destroy fails for some reason.
+	 */
+	public void destroy() throws FilesystemAccessException;
+	// TODO: Permissions (or decide not to do anything about them)
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/File.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/File.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/File.java
new file mode 100644
index 0000000..97510e4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/File.java
@@ -0,0 +1,82 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+/**
+ * Represents a file in the working directory of a workflow instance run, or in
+ * some sub-directory of it.
+ * 
+ * @author Donal Fellows
+ * @see Directory
+ */
+public interface File extends DirectoryEntry {
+	/**
+	 * @param offset
+	 *            Where in the file to start reading.
+	 * @param length
+	 *            The length of file to read, or -1 to read to the end of the
+	 *            file.
+	 * @return The literal byte contents of the section of the file, or null if
+	 *         the section doesn't exist.
+	 * @throws FilesystemAccessException
+	 *             If the read of the file goes wrong.
+	 */
+	public byte[] getContents(int offset, int length)
+			throws FilesystemAccessException;
+
+	/**
+	 * 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 FilesystemAccessException
+	 *             If the write to the file goes wrong.
+	 */
+	public void setContents(byte[] data) throws FilesystemAccessException;
+
+	/**
+	 * Append the data to the file.
+	 * 
+	 * @param data
+	 *            The literal bytes that will be added on to the end of the
+	 *            file.
+	 * @throws FilesystemAccessException
+	 *             If the write to the file goes wrong.
+	 */
+	public void appendContents(byte[] data) throws FilesystemAccessException;
+
+	/**
+	 * @return The length of the file, in bytes.
+	 * @throws FilesystemAccessException
+	 *             If the read of the file size goes wrong.
+	 */
+	public long getSize() throws FilesystemAccessException;
+
+	/**
+	 * Asks for the argument file to be copied to this one.
+	 * 
+	 * @param from
+	 *            The source file.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	public void copy(File from) throws FilesystemAccessException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Input.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Input.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Input.java
new file mode 100644
index 0000000..5d92f67
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Input.java
@@ -0,0 +1,105 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+/**
+ * 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 Input {
+	/**
+	 * @return The file currently assigned to this input port, or <tt>null</tt>
+	 *         if no file is assigned.
+	 */
+	@Nullable
+	public String getFile();
+
+	/**
+	 * @return The name of this input port. This may not be changed.
+	 */
+	@Nonnull
+	public String getName();
+
+	/**
+	 * @return The value currently assigned to this input port, or <tt>null</tt>
+	 *         if no value is assigned.
+	 */
+	@Nullable
+	public String getValue();
+
+	/**
+	 * @return The delimiter for the input port, or <tt>null</tt> if the value
+	 *         is not to be split.
+	 */
+	@Nullable
+	public String getDelimiter();
+
+	/**
+	 * 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 FilesystemAccessException
+	 *             If the filename is invalid.
+	 * @throws BadStateChangeException
+	 *             If the run isn't in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	public void setFile(String file) throws FilesystemAccessException,
+			BadStateChangeException;
+
+	/**
+	 * 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 BadStateChangeException
+	 *             If the run isn't in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	public void setValue(String value) throws BadStateChangeException;
+
+	/**
+	 * Sets (or clears) the delimiter for the input port.
+	 * 
+	 * @param delimiter
+	 *            The delimiter character, or <tt>null</tt> if the value is not
+	 *            to be split.
+	 * @throws BadStateChangeException
+	 *             If the run isn't in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	@Nullable
+	public void setDelimiter(String delimiter) throws BadStateChangeException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Listener.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Listener.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Listener.java
new file mode 100644
index 0000000..5fee6cc
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/Listener.java
@@ -0,0 +1,77 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+import org.taverna.server.master.exceptions.NoListenerException;
+
+/**
+ * An event listener that can be attached to a {@link TavernaRun}.
+ * 
+ * @author Donal Fellows
+ */
+public interface Listener {
+	/**
+	 * @return The name of the listener.
+	 */
+	public String getName();
+
+	/**
+	 * @return The type of the listener.
+	 */
+	public String getType();
+
+	/**
+	 * @return The configuration document for the listener.
+	 */
+	public String getConfiguration();
+
+	/**
+	 * @return The supported properties of the listener.
+	 */
+	public String[] listProperties();
+
+	/**
+	 * 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 NoListenerException
+	 *             If no property with that name exists.
+	 */
+	public String getProperty(String propName) throws NoListenerException;
+
+	/**
+	 * 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 NoListenerException
+	 *             If no property with that name exists.
+	 * @throws BadPropertyValueException
+	 *             If the value of the property is bad (e.g., wrong syntax).
+	 */
+	public void setProperty(String propName, String value)
+			throws NoListenerException, BadPropertyValueException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/LocalIdentityMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/LocalIdentityMapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/LocalIdentityMapper.java
new file mode 100644
index 0000000..becc55c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/LocalIdentityMapper.java
@@ -0,0 +1,42 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * This interface describes how to map from the identity understood by the
+ * webapp to the identity understood by the local execution system.
+ * 
+ * @author Donal Fellows
+ */
+public interface LocalIdentityMapper {
+	/**
+	 * Given a user's identity, get the local identity to use for executing
+	 * their workflows. Note that it is assumed that there will never be a
+	 * failure from this interface; it is <i>not</i> a security policy
+	 * decision or enforcement point.
+	 * 
+	 * @param user
+	 *            An identity token.
+	 * @return A user name, which must be defined in the context that workflows
+	 *         will be running in.
+	 */
+	public String getUsernameForPrincipal(UsernamePrincipal user);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/MessageDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/MessageDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/MessageDispatcher.java
new file mode 100644
index 0000000..b3e0260
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/interfaces/MessageDispatcher.java
@@ -0,0 +1,58 @@
+/*
+ */
+package org.taverna.server.master.interfaces;
+/*
+ * 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.
+ */
+
+import javax.annotation.Nonnull;
+
+/**
+ * The interface supported by all notification message dispatchers.
+ * @author Donal Fellows
+ */
+public interface MessageDispatcher {
+	/**
+	 * @return Whether this message dispatcher is actually available (fully
+	 *         configured, etc.)
+	 */
+	boolean isAvailable();
+
+	/**
+	 * @return The name of this dispatcher, which must match the protocol
+	 *         supported by it (for a non-universal dispatcher) and the name of
+	 *         the message generator used to produce the message.
+	 */
+	String getName();
+
+	/**
+	 * Dispatch a message to a recipient.
+	 * 
+	 * @param originator
+	 *            The workflow run that produced the message.
+	 * @param messageSubject
+	 *            The subject of the message to send.
+	 * @param messageContent
+	 *            The plain-text content of the message to send.
+	 * @param targetParameter
+	 *            A description of where it is to go.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	void dispatch(@Nonnull TavernaRun originator,
+			@Nonnull String messageSubject, @Nonnull String messageContent,
+			@Nonnull String targetParameter) throws Exception;
+}
\ No newline at end of file


[32/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServerSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServerSupport.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServerSupport.java
new file mode 100644
index 0000000..533acf5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/TavernaServerSupport.java
@@ -0,0 +1,970 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static eu.medsea.util.MimeUtil.UNKNOWN_MIME_TYPE;
+import static eu.medsea.util.MimeUtil.getExtensionMimeTypes;
+import static eu.medsea.util.MimeUtil.getMimeType;
+import static java.lang.Math.min;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.springframework.jmx.support.MetricType.COUNTER;
+import static org.springframework.jmx.support.MetricType.GAUGE;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.taverna.server.master.common.Roles.ADMIN;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.activation.DataHandler;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.PreDestroy;
+import javax.ws.rs.WebApplicationException;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedMetric;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.taverna.server.master.api.ManagementModel;
+import org.taverna.server.master.api.TavernaServerBean;
+import org.taverna.server.master.common.Capability;
+import org.taverna.server.master.common.Permission;
+import org.taverna.server.master.common.ProfileList;
+import org.taverna.server.master.common.VersionedElement;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.common.version.Version;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.factories.ListenerFactory;
+import org.taverna.server.master.factories.RunFactory;
+import org.taverna.server.master.identity.WorkflowInternalAuthProvider.WorkflowSelfAuthority;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.Input;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.RunStore;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.rest.handler.T2FlowDocumentHandler;
+import org.taverna.server.master.utils.CapabilityLister;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.master.utils.InvocationCounter;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+import org.apache.taverna.scufl2.api.profiles.Profile;
+
+/**
+ * Web application support utilities.
+ * 
+ * @author Donal Fellows
+ */
+@ManagedResource(objectName = JMX_ROOT + "Webapp", description = "The main Taverna Server "
+		+ Version.JAVA + " web-application interface.")
+public class TavernaServerSupport {
+	/** The main webapp log. */
+	private Log log = getLog("Taverna.Server.Webapp");
+	private Log accessLog = getLog("Taverna.Server.Webapp.Access");;
+	/** Bean used to log counts of external calls. */
+	private InvocationCounter counter;
+	/** A storage facility for workflow runs. */
+	private RunStore runStore;
+	/** Encapsulates the policies applied by this server. */
+	private Policy policy;
+	/** Connection to the persistent state of this service. */
+	private ManagementModel stateModel;
+	/** A factory for event listeners to attach to workflow runs. */
+	private ListenerFactory listenerFactory;
+	/** A factory for workflow runs. */
+	private RunFactory runFactory;
+	/** How to map the user ID to who to run as. */
+	private LocalIdentityMapper idMapper;
+	/** The code that is coupled to CXF. */
+	private TavernaServerBean webapp;
+	/** How to handle files. */
+	private FilenameUtils fileUtils;
+	/** How to get the server capabilities. */
+	private CapabilityLister capabilitySource;
+	/**
+	 * Whether to log failures during principal retrieval. Should be normally on
+	 * as it indicates a serious problem, but can be switched off for testing.
+	 */
+	private boolean logGetPrincipalFailures = true;
+	private Map<String, String> contentTypeMap;
+	/** Number of bytes to read when guessing the MIME type. */
+	private static final int SAMPLE_SIZE = 1024;
+	/** Number of bytes to ask for when copying a stream to a file. */
+	private static final int TRANSFER_SIZE = 32768;
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	/**
+	 * @return Count of the number of external calls into this webapp.
+	 */
+	@ManagedMetric(description = "Count of the number of external calls into this webapp.", metricType = COUNTER, category = "throughput")
+	public int getInvocationCount() {
+		return counter.getCount();
+	}
+
+	/**
+	 * @return Current number of runs.
+	 */
+	@ManagedMetric(description = "Current number of runs.", metricType = GAUGE, category = "utilization")
+	public int getCurrentRunCount() {
+		return runStore.listRuns(null, policy).size();
+	}
+
+	/**
+	 * @return Whether to write submitted workflows to the log.
+	 */
+	@ManagedAttribute(description = "Whether to write submitted workflows to the log.")
+	public boolean getLogIncomingWorkflows() {
+		return stateModel.getLogIncomingWorkflows();
+	}
+
+	/**
+	 * @param logIncomingWorkflows
+	 *            Whether to write submitted workflows to the log.
+	 */
+	@ManagedAttribute(description = "Whether to write submitted workflows to the log.")
+	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
+		stateModel.setLogIncomingWorkflows(logIncomingWorkflows);
+	}
+
+	/**
+	 * @return Whether outgoing exceptions should be logged before being
+	 *         converted to responses.
+	 */
+	@ManagedAttribute(description = "Whether outgoing exceptions should be logged before being converted to responses.")
+	public boolean getLogOutgoingExceptions() {
+		return stateModel.getLogOutgoingExceptions();
+	}
+
+	/**
+	 * @param logOutgoing
+	 *            Whether outgoing exceptions should be logged before being
+	 *            converted to responses.
+	 */
+	@ManagedAttribute(description = "Whether outgoing exceptions should be logged before being converted to responses.")
+	public void setLogOutgoingExceptions(boolean logOutgoing) {
+		stateModel.setLogOutgoingExceptions(logOutgoing);
+	}
+
+	/**
+	 * @return Whether to permit any new workflow runs to be created.
+	 */
+	@ManagedAttribute(description = "Whether to permit any new workflow runs to be created; has no effect on existing runs.")
+	public boolean getAllowNewWorkflowRuns() {
+		return stateModel.getAllowNewWorkflowRuns();
+	}
+
+	/**
+	 * @param allowNewWorkflowRuns
+	 *            Whether to permit any new workflow runs to be created.
+	 */
+	@ManagedAttribute(description = "Whether to permit any new workflow runs to be created; has no effect on existing runs.")
+	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
+		stateModel.setAllowNewWorkflowRuns(allowNewWorkflowRuns);
+	}
+
+	/**
+	 * @return The server's version identifier.
+	 */
+	@ManagedAttribute(description = "The installed version of the server.")
+	public String getServerVersion() {
+		return VersionedElement.VERSION + " " + VersionedElement.REVISION + " "
+				+ VersionedElement.TIMESTAMP;
+	}
+
+	@ManagedAttribute(description = "The URIs of the workfows that this server will allow to be instantiated.")
+	public URI[] getPermittedWorkflowURIs() {
+		List<URI> pw = policy.listPermittedWorkflowURIs(null);
+		if (pw == null)
+			return new URI[0];
+		return pw.toArray(new URI[pw.size()]);
+	}
+
+	@ManagedAttribute(description = "The URIs of the workfows that this server will allow to be instantiated.")
+	public void setPermittedWorkflowURIs(URI[] pw) {
+		if (pw == null)
+			policy.setPermittedWorkflowURIs(null, new ArrayList<URI>());
+		else
+			policy.setPermittedWorkflowURIs(null, Arrays.asList(pw));
+	}
+
+	public int getMaxSimultaneousRuns() {
+		Integer limit = policy.getMaxRuns(getPrincipal());
+		if (limit == null)
+			return policy.getMaxRuns();
+		return min(limit.intValue(), policy.getMaxRuns());
+	}
+
+	@Autowired
+	private T2FlowDocumentHandler t2flowHandler;
+
+	public Workflow getWorkflowDocumentFromURI(URI uri)
+			throws WebApplicationException, IOException {
+		URLConnection conn = uri.toURL().openConnection();
+		conn.setRequestProperty("Accept", T2FLOW);
+		conn.connect();
+		// Tricky point: we know the reader part of the handler only cares
+		// about the stream argument.
+		return t2flowHandler.readFrom(null, null, null, null, null,
+				conn.getInputStream());
+	}
+
+	public List<String> getListenerTypes() {
+		return listenerFactory.getSupportedListenerTypes();
+	}
+
+	/**
+	 * @param policy
+	 *            The policy being installed by Spring.
+	 */
+	@Required
+	public void setPolicy(Policy policy) {
+		this.policy = policy;
+	}
+
+	/**
+	 * @param listenerFactory
+	 *            The listener factory being installed by Spring.
+	 */
+	@Required
+	public void setListenerFactory(ListenerFactory listenerFactory) {
+		this.listenerFactory = listenerFactory;
+	}
+
+	/**
+	 * @param runFactory
+	 *            The run factory being installed by Spring.
+	 */
+	@Required
+	public void setRunFactory(RunFactory runFactory) {
+		this.runFactory = runFactory;
+	}
+
+	/**
+	 * @param runStore
+	 *            The run store being installed by Spring.
+	 */
+	@Required
+	public void setRunStore(RunStore runStore) {
+		this.runStore = runStore;
+	}
+
+	/**
+	 * @param stateModel
+	 *            The state model engine being installed by Spring.
+	 */
+	@Required
+	public void setStateModel(ManagementModel stateModel) {
+		this.stateModel = stateModel;
+	}
+
+	/**
+	 * @param mapper
+	 *            The identity mapper being installed by Spring.
+	 */
+	@Required
+	public void setIdMapper(LocalIdentityMapper mapper) {
+		this.idMapper = mapper;
+	}
+
+	/**
+	 * @param counter
+	 *            The object whose job it is to manage the counting of
+	 *            invocations. Installed by Spring.
+	 */
+	@Required
+	public void setInvocationCounter(InvocationCounter counter) {
+		this.counter = counter;
+	}
+
+	/**
+	 * @param webapp
+	 *            The web-app being installed by Spring.
+	 */
+	@Required
+	public void setWebapp(TavernaServerBean webapp) {
+		this.webapp = webapp;
+	}
+
+	/**
+	 * @param fileUtils
+	 *            The file handling utilities.
+	 */
+	@Required
+	public void setFileUtils(FilenameUtils fileUtils) {
+		this.fileUtils = fileUtils;
+	}
+
+	/**
+	 * @param logthem
+	 *            Whether to log failures relating to principals.
+	 */
+	public void setLogGetPrincipalFailures(boolean logthem) {
+		logGetPrincipalFailures = logthem;
+	}
+
+	public Map<String, String> getContentTypeMap() {
+		return contentTypeMap;
+	}
+
+	/**
+	 * Mapping from filename suffixes (e.g., "baclava") to content types.
+	 * 
+	 * @param contentTypeMap
+	 *            The mapping to install.
+	 */
+	@Required
+	public void setContentTypeMap(Map<String, String> contentTypeMap) {
+		this.contentTypeMap = contentTypeMap;
+	}
+
+	@Required
+	public void setCapabilitySource(CapabilityLister capabilitySource) {
+		this.capabilitySource = capabilitySource;
+	}
+
+	/**
+	 * Test whether the current user can do updates to the given run.
+	 * 
+	 * @param run
+	 *            The workflow run to do the test on.
+	 * @throws NoUpdateException
+	 *             If the current user is not permitted to update the run.
+	 */
+	public void permitUpdate(@Nonnull TavernaRun run) throws NoUpdateException {
+		if (isSuperUser()) {
+			accessLog
+					.warn("check for admin powers passed; elevated access rights granted for update");
+			return; // Superusers are fully authorized to access others things
+		}
+		if (getSelfAuthority() != null) {
+			// At this point, must already be accessing self as that is checked
+			// in getRun().
+			return;
+		}
+		policy.permitUpdate(getPrincipal(), run);
+	}
+
+	/**
+	 * Test whether the current user can destroy or control the lifespan of the
+	 * given run.
+	 * 
+	 * @param run
+	 *            The workflow run to do the test on.
+	 * @throws NoDestroyException
+	 *             If the current user is not permitted to destroy the run.
+	 */
+	public void permitDestroy(TavernaRun run) throws NoDestroyException {
+		if (isSuperUser()) {
+			accessLog
+					.warn("check for admin powers passed; elevated access rights granted for destroy");
+			return; // Superusers are fully authorized to access others things
+		}
+		if (getSelfAuthority() != null)
+			throw new NoDestroyException();
+		policy.permitDestroy(getPrincipal(), run);
+	}
+
+	/**
+	 * Gets the identity of the user currently accessing the webapp, which is
+	 * stored in a thread-safe way in the webapp's container's context.
+	 * 
+	 * @return The identity of the user accessing the webapp.
+	 */
+	@Nonnull
+	public UsernamePrincipal getPrincipal() {
+		try {
+			Authentication auth = SecurityContextHolder.getContext()
+					.getAuthentication();
+			if (auth == null || !auth.isAuthenticated()) {
+				if (logGetPrincipalFailures)
+					log.warn("failed to get auth; going with <NOBODY>");
+				return new UsernamePrincipal("<NOBODY>");
+			}
+			return new UsernamePrincipal(auth);
+		} catch (RuntimeException e) {
+			if (logGetPrincipalFailures)
+				log.info("failed to map principal", e);
+			throw e;
+		}
+	}
+
+	private WorkflowSelfAuthority getSelfAuthority() {
+		try {
+			Authentication a = SecurityContextHolder.getContext()
+					.getAuthentication();
+			for (GrantedAuthority ga : a.getAuthorities())
+				if (ga instanceof WorkflowSelfAuthority)
+					return (WorkflowSelfAuthority) ga;
+		} catch (RuntimeException e) {
+		}
+		return null;
+	}
+
+	/**
+	 * Obtain the workflow run with a particular name.
+	 * 
+	 * @param name
+	 *            The name of the run to look up.
+	 * @return A workflow run handle that the current user has at least
+	 *         permission to read.
+	 * @throws UnknownRunException
+	 *             If the workflow run doesn't exist or the current user doesn't
+	 *             have permission to see it.
+	 */
+	@Nonnull
+	public TavernaRun getRun(@Nonnull String name) throws UnknownRunException {
+		if (isSuperUser()) {
+			accessLog
+					.info("check for admin powers passed; elevated access rights granted for read");
+			return runStore.getRun(name);
+		}
+		WorkflowSelfAuthority wsa = getSelfAuthority();
+		if (wsa != null) {
+			if (wsa.getWorkflowID().equals(name))
+				return runStore.getRun(name);
+			throw new UnknownRunException();
+		}
+		return runStore.getRun(getPrincipal(), policy, name);
+	}
+
+	/**
+	 * Construct a listener attached to the given run.
+	 * 
+	 * @param run
+	 *            The workflow run to attach the listener to.
+	 * @param type
+	 *            The name of the type of run to create.
+	 * @param configuration
+	 *            The configuration description to pass into the listener. The
+	 *            format of this string is up to the listener to define.
+	 * @return A handle to the listener which can be used to further configure
+	 *         any properties.
+	 * @throws NoListenerException
+	 *             If the listener type is unrecognized or the configuration is
+	 *             invalid.
+	 * @throws NoUpdateException
+	 *             If the run does not permit the current user to add listeners
+	 *             (or perform other types of update).
+	 */
+	@Nonnull
+	public Listener makeListener(@Nonnull TavernaRun run, @Nonnull String type,
+			@Nonnull String configuration) throws NoListenerException,
+			NoUpdateException {
+		permitUpdate(run);
+		return listenerFactory.makeListener(run, type, configuration);
+	}
+
+	/**
+	 * Obtain a listener that is already attached to a workflow run.
+	 * 
+	 * @param run
+	 *            The workflow run to search.
+	 * @param listenerName
+	 *            The name of the listener to look up.
+	 * @return The listener instance interface.
+	 * @throws NoListenerException
+	 *             If no listener with that name exists.
+	 */
+	@Nonnull
+	public Listener getListener(TavernaRun run, String listenerName)
+			throws NoListenerException {
+		for (Listener l : run.getListeners())
+			if (l.getName().equals(listenerName))
+				return l;
+		throw new NoListenerException();
+	}
+
+	/**
+	 * Obtain a property from a listener that is already attached to a workflow
+	 * run.
+	 * 
+	 * @param runName
+	 *            The ID of the workflow run to search.
+	 * @param listenerName
+	 *            The name of the listener to look up in.
+	 * @param propertyName
+	 *            The name of the property to fetch.
+	 * @return The property value.
+	 * @throws NoListenerException
+	 *             If no listener with that name exists, or no property with
+	 *             that name exists.
+	 * @throws UnknownRunException
+	 *             If no run with that name exists.
+	 */
+	@Nonnull
+	public String getProperty(String runName, String listenerName,
+			String propertyName) throws NoListenerException,
+			UnknownRunException {
+		return getListener(runName, listenerName).getProperty(propertyName);
+	}
+
+	/**
+	 * Obtain a property from a listener that is already attached to a workflow
+	 * run.
+	 * 
+	 * @param run
+	 *            The workflow run to search.
+	 * @param listenerName
+	 *            The name of the listener to look up in.
+	 * @param propertyName
+	 *            The name of the property to fetch.
+	 * @return The property value.
+	 * @throws NoListenerException
+	 *             If no listener with that name exists, or no property with
+	 *             that name exists.
+	 */
+	@Nonnull
+	public String getProperty(TavernaRun run, String listenerName,
+			String propertyName) throws NoListenerException {
+		return getListener(run, listenerName).getProperty(propertyName);
+	}
+
+	/**
+	 * Get the permission description for the given user.
+	 * 
+	 * @param context
+	 *            A security context associated with a particular workflow run.
+	 *            Note that only the owner of a workflow run may get the
+	 *            security context in the first place.
+	 * @param userName
+	 *            The name of the user to look up the permission for.
+	 * @return A permission description.
+	 */
+	@Nonnull
+	public Permission getPermission(@Nonnull TavernaSecurityContext context,
+			@Nonnull String userName) {
+		if (context.getPermittedDestroyers().contains(userName))
+			return Permission.Destroy;
+		if (context.getPermittedUpdaters().contains(userName))
+			return Permission.Update;
+		if (context.getPermittedReaders().contains(userName))
+			return Permission.Read;
+		return Permission.None;
+	}
+
+	/**
+	 * Set the permissions for the given user.
+	 * 
+	 * @param context
+	 *            A security context associated with a particular workflow run.
+	 *            Note that only the owner of a workflow run may get the
+	 *            security context in the first place.
+	 * @param userName
+	 *            The name of the user to set the permission for.
+	 * @param permission
+	 *            The description of the permission to grant. Note that the
+	 *            owner of a workflow run always has the equivalent of
+	 *            {@link Permission#Destroy}; this is always enforced before
+	 *            checking for other permissions.
+	 */
+	public void setPermission(TavernaSecurityContext context, String userName,
+			Permission permission) {
+		Set<String> permSet;
+		boolean doRead = false, doWrite = false, doKill = false;
+
+		switch (permission) {
+		case Destroy:
+			doKill = true;
+		case Update:
+			doWrite = true;
+		case Read:
+			doRead = true;
+		default:
+			break;
+		}
+
+		permSet = context.getPermittedReaders();
+		if (doRead) {
+			if (!permSet.contains(userName)) {
+				permSet = new HashSet<>(permSet);
+				permSet.add(userName);
+				context.setPermittedReaders(permSet);
+			}
+		} else if (permSet.contains(userName)) {
+			permSet = new HashSet<>(permSet);
+			permSet.remove(userName);
+			context.setPermittedReaders(permSet);
+		}
+
+		permSet = context.getPermittedUpdaters();
+		if (doWrite) {
+			if (!permSet.contains(userName)) {
+				permSet = new HashSet<>(permSet);
+				permSet.add(userName);
+				context.setPermittedUpdaters(permSet);
+			}
+		} else if (permSet.contains(userName)) {
+			permSet = new HashSet<>(permSet);
+			permSet.remove(userName);
+			context.setPermittedUpdaters(permSet);
+		}
+
+		permSet = context.getPermittedDestroyers();
+		if (doKill) {
+			if (!permSet.contains(userName)) {
+				permSet = new HashSet<>(permSet);
+				permSet.add(userName);
+				context.setPermittedDestroyers(permSet);
+			}
+		} else if (permSet.contains(userName)) {
+			permSet = new HashSet<>(permSet);
+			permSet.remove(userName);
+			context.setPermittedDestroyers(permSet);
+		}
+	}
+
+	public Map<String, Permission> getPermissionMap(
+			TavernaSecurityContext context) {
+		Map<String, Permission> perm = new HashMap<>();
+		for (String u : context.getPermittedReaders())
+			perm.put(u, Permission.Read);
+		for (String u : context.getPermittedUpdaters())
+			perm.put(u, Permission.Update);
+		for (String u : context.getPermittedDestroyers())
+			perm.put(u, Permission.Destroy);
+		return perm;
+	}
+
+	/**
+	 * Stops a run from being possible to be looked up and destroys it.
+	 * 
+	 * @param runName
+	 *            The name of the run.
+	 * @param run
+	 *            The workflow run. <i>Must</i> correspond to the name.
+	 * @throws NoDestroyException
+	 *             If the user is not permitted to destroy the workflow run.
+	 * @throws UnknownRunException
+	 *             If the run is unknown (e.g., because it is already
+	 *             destroyed).
+	 */
+	public void unregisterRun(@Nonnull String runName, @Nonnull TavernaRun run)
+			throws NoDestroyException, UnknownRunException {
+		if (run == null)
+			run = getRun(runName);
+		permitDestroy(run);
+		runStore.unregisterRun(runName);
+		run.destroy();
+	}
+
+	/**
+	 * Changes the expiry date of a workflow run. The expiry date is when the
+	 * workflow run becomes eligible for automated destruction.
+	 * 
+	 * @param run
+	 *            The handle to the workflow run.
+	 * @param date
+	 *            When the workflow run should be expired.
+	 * @return When the workflow run will actually be expired.
+	 * @throws NoDestroyException
+	 *             If the user is not permitted to destroy the workflow run.
+	 *             (Note that lifespan management requires the ability to
+	 *             destroy.)
+	 */
+	@Nonnull
+	public Date updateExpiry(@Nonnull TavernaRun run, @Nonnull Date date)
+			throws NoDestroyException {
+		permitDestroy(run);
+		run.setExpiry(date);
+		return run.getExpiry();
+	}
+
+	/**
+	 * Manufacture a workflow run instance.
+	 * 
+	 * @param workflow
+	 *            The workflow document (t2flow, scufl2?) to instantiate.
+	 * @return The ID of the created workflow run.
+	 * @throws NoCreateException
+	 *             If the user is not permitted to create workflows.
+	 */
+	public String buildWorkflow(Workflow workflow) throws NoCreateException {
+		UsernamePrincipal p = getPrincipal();
+		if (getSelfAuthority() != null)
+			throw new NoCreateException(
+					"runs may not create workflows on their host server");
+		if (!stateModel.getAllowNewWorkflowRuns())
+			throw new NoCreateException("run creation not currently enabled");
+		try {
+			if (stateModel.getLogIncomingWorkflows()) {
+				log.info(workflow.marshal());
+			}
+		} catch (JAXBException e) {
+			log.warn("problem when logging workflow", e);
+		}
+
+		// Security checks
+		policy.permitCreate(p, workflow);
+		if (idMapper != null && idMapper.getUsernameForPrincipal(p) == null) {
+			log.error("cannot map principal to local user id");
+			throw new NoCreateException(
+					"failed to map security token to local user id");
+		}
+
+		TavernaRun run;
+		try {
+			run = runFactory.create(p, workflow);
+			TavernaSecurityContext c = run.getSecurityContext();
+			c.initializeSecurityFromContext(SecurityContextHolder.getContext());
+			/*
+			 * These next pieces of security initialisation are (hopefully)
+			 * obsolete now that we use Spring Security, but we keep them Just
+			 * In Case.
+			 */
+			boolean doRESTinit = webapp.initObsoleteSOAPSecurity(c);
+			if (doRESTinit)
+				webapp.initObsoleteRESTSecurity(c);
+		} catch (Exception e) {
+			log.error("failed to build workflow run worker", e);
+			throw new NoCreateException("failed to build workflow run worker");
+		}
+
+		return runStore.registerRun(run);
+	}
+
+	private boolean isSuperUser() {
+		try {
+			Authentication auth = SecurityContextHolder.getContext()
+					.getAuthentication();
+			if (auth == null || !auth.isAuthenticated())
+				return false;
+			UserDetails details = (UserDetails) auth.getPrincipal();
+			if (log.isDebugEnabled())
+				log.debug("checking for admin role for user <" + auth.getName()
+						+ "> in collection " + details.getAuthorities());
+			return details.getAuthorities().contains(ADMIN);
+		} catch (ClassCastException e) {
+			return false;
+		}
+	}
+
+	/**
+	 * Get a particular input to a workflow run.
+	 * 
+	 * @param run
+	 *            The workflow run to search.
+	 * @param portName
+	 *            The name of the input.
+	 * @return The handle of the input, or <tt>null</tt> if no such handle
+	 *         exists.
+	 */
+	@Nullable
+	public Input getInput(TavernaRun run, String portName) {
+		for (Input i : run.getInputs())
+			if (i.getName().equals(portName))
+				return i;
+		return null;
+	}
+
+	/**
+	 * Get a listener attached to a run.
+	 * 
+	 * @param runName
+	 *            The name of the run to look up
+	 * @param listenerName
+	 *            The name of the listener.
+	 * @return The handle of the listener.
+	 * @throws NoListenerException
+	 *             If no such listener exists.
+	 * @throws UnknownRunException
+	 *             If no such workflow run exists, or if the user does not have
+	 *             permission to access it.
+	 */
+	public Listener getListener(String runName, String listenerName)
+			throws NoListenerException, UnknownRunException {
+		return getListener(getRun(runName), listenerName);
+	}
+
+	/**
+	 * Given a file, produce a guess at its content type. This uses the content
+	 * type map property, and if that search fails it falls back on the Medsea
+	 * mime type library.
+	 * 
+	 * @param f
+	 *            The file handle.
+	 * @return The content type. If all else fails, produces good old
+	 *         "application/octet-stream".
+	 */
+	@Nonnull
+	public String getEstimatedContentType(@Nonnull File f) {
+		String name = f.getName();
+		for (int idx = name.indexOf('.'); idx != -1; idx = name.indexOf('.',
+				idx + 1)) {
+			String mt = contentTypeMap.get(name.substring(idx + 1));
+			if (mt != null)
+				return mt;
+		}
+		@Nonnull
+		String type = getExtensionMimeTypes(name);
+		if (!type.equals(UNKNOWN_MIME_TYPE))
+			return type;
+		try {
+			return getMimeType(new ByteArrayInputStream(f.getContents(0,
+					SAMPLE_SIZE)));
+		} catch (FilesystemAccessException e) {
+			return type;
+		}
+	}
+
+	public void copyDataToFile(DataHandler handler, File file)
+			throws FilesystemAccessException {
+		try {
+			copyStreamToFile(handler.getInputStream(), file);
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"problem constructing stream from data source", e);
+		}
+	}
+
+	public void copyDataToFile(URI uri, File file)
+			throws MalformedURLException, FilesystemAccessException,
+			IOException {
+		copyStreamToFile(uri.toURL().openStream(), file);
+	}
+
+	public void copyStreamToFile(InputStream stream, File file)
+			throws FilesystemAccessException {
+		String name = file.getFullName();
+		long total = 0;
+		try {
+			byte[] buffer = new byte[TRANSFER_SIZE];
+			boolean first = true;
+			while (true) {
+				int len = stream.read(buffer);
+				if (len < 0)
+					break;
+				total += len;
+				if (log.isDebugEnabled())
+					log.debug("read " + len
+							+ " bytes from source stream (total: " + total
+							+ ") bound for " + name);
+				if (len == buffer.length) {
+					if (first)
+						file.setContents(buffer);
+					else
+						file.appendContents(buffer);
+				} else {
+					byte[] newBuf = new byte[len];
+					System.arraycopy(buffer, 0, newBuf, 0, len);
+					if (first)
+						file.setContents(newBuf);
+					else
+						file.appendContents(newBuf);
+				}
+				first = false;
+			}
+		} catch (IOException exn) {
+			throw new FilesystemAccessException("failed to transfer bytes", exn);
+		}
+	}
+
+	/**
+	 * Build a description of the profiles supported by a workflow. Note that we
+	 * expect the set of profiles to be fairly small.
+	 * 
+	 * @param workflow
+	 *            The workflow to describe the profiles of.
+	 * @return The descriptor (which might be empty).
+	 */
+	public ProfileList getProfileDescriptor(Workflow workflow) {
+		ProfileList result = new ProfileList();
+		String main = workflow.getMainProfileName();
+		for (Profile p : workflow.getProfiles()) {
+			ProfileList.Info i = new ProfileList.Info();
+			i.name = p.getName();
+			if (main != null && main.equals(i.name))
+				i.main = true;
+			result.profile.add(i);
+		}
+		return result;
+	}
+
+	public boolean getAllowStartWorkflowRuns() {
+		return runFactory.isAllowingRunsToStart();
+	}
+
+	/**
+	 * The list of filenames that logs may occupy.
+	 */
+	private static final String[] LOGS = { "logs/detail.log.4",
+			"logs/detail.log.3", "logs/detail.log.2", "logs/detail.log.1",
+			"logs/detail.log" };
+
+	public FileConcatenation getLogs(TavernaRun run) {
+		FileConcatenation fc = new FileConcatenation();
+		for (String name : LOGS) {
+			try {
+				fc.add(fileUtils.getFile(run, name));
+			} catch (FilesystemAccessException | NoDirectoryEntryException e) {
+				// Ignore
+			}
+		}
+		return fc;
+	}
+
+	@Nonnull
+	public List<Capability> getCapabilities() {
+		return capabilitySource.getCapabilities();
+	}
+
+	static final String PROV_BUNDLE = "out.bundle.zip";
+
+	public FileConcatenation getProv(TavernaRun run) {
+		FileConcatenation fc = new FileConcatenation();
+		try {
+			fc.add(fileUtils.getFile(run, PROV_BUNDLE));
+		} catch (FilesystemAccessException | NoDirectoryEntryException e) {
+			// Ignore
+		}
+		return fc;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/Admin.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/Admin.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/Admin.java
new file mode 100644
index 0000000..03c0c8b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/Admin.java
@@ -0,0 +1,1113 @@
+/*
+ */
+package org.taverna.server.master.admin;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.admin.Paths.ALLOW_NEW;
+import static org.taverna.server.master.admin.Paths.ARGS;
+import static org.taverna.server.master.admin.Paths.EXEC_WF;
+import static org.taverna.server.master.admin.Paths.EXITCODE;
+import static org.taverna.server.master.admin.Paths.FACTORIES;
+import static org.taverna.server.master.admin.Paths.GEN_PROV;
+import static org.taverna.server.master.admin.Paths.INVOKES;
+import static org.taverna.server.master.admin.Paths.JAR_FORKER;
+import static org.taverna.server.master.admin.Paths.JAR_WORKER;
+import static org.taverna.server.master.admin.Paths.JAVA;
+import static org.taverna.server.master.admin.Paths.LIFE;
+import static org.taverna.server.master.admin.Paths.LOG_EXN;
+import static org.taverna.server.master.admin.Paths.LOG_WFS;
+import static org.taverna.server.master.admin.Paths.OPERATING;
+import static org.taverna.server.master.admin.Paths.OP_LIMIT;
+import static org.taverna.server.master.admin.Paths.PASSFILE;
+import static org.taverna.server.master.admin.Paths.PERM_WF;
+import static org.taverna.server.master.admin.Paths.REG_HOST;
+import static org.taverna.server.master.admin.Paths.REG_JAR;
+import static org.taverna.server.master.admin.Paths.REG_POLL;
+import static org.taverna.server.master.admin.Paths.REG_PORT;
+import static org.taverna.server.master.admin.Paths.REG_WAIT;
+import static org.taverna.server.master.admin.Paths.ROOT;
+import static org.taverna.server.master.admin.Paths.RUNS;
+import static org.taverna.server.master.admin.Paths.RUN_LIMIT;
+import static org.taverna.server.master.admin.Paths.STARTUP;
+import static org.taverna.server.master.admin.Paths.TOTAL_RUNS;
+import static org.taverna.server.master.admin.Paths.URS;
+import static org.taverna.server.master.admin.Paths.UR_FILE;
+import static org.taverna.server.master.admin.Paths.USER;
+import static org.taverna.server.master.admin.Paths.USERS;
+import static org.taverna.server.master.admin.Types.JSON;
+import static org.taverna.server.master.admin.Types.PLAIN;
+import static org.taverna.server.master.admin.Types.XML;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.taverna.server.usagerecord.JobUsageRecord;
+import org.taverna.server.master.common.Uri;
+import org.taverna.server.master.common.VersionedElement;
+
+/**
+ * The administration interface for Taverna Server.
+ * 
+ * @author Donal Fellows
+ */
+@Description("Administration interface for Taverna Server.")
+public interface Admin {
+	/**
+	 * Get a simple administration user interface.
+	 * 
+	 * @return The description document in a response.
+	 * @throws IOException
+	 */
+	@GET
+	@Path(ROOT)
+	@Produces("text/html")
+	@Nonnull
+	Response getUserInterface() throws IOException;
+
+	/**
+	 * Gets support resources for the administration user interface.
+	 * 
+	 * @param file
+	 *            The name of the static resource to provide.
+	 * @return The requested document in a response.
+	 * @throws IOException
+	 */
+	@GET
+	@Path("static/{file}")
+	@Produces("*/*")
+	Response getStaticResource(@PathParam("file") String file)
+			throws IOException;
+
+	/**
+	 * Get a description of the administration interface.
+	 * 
+	 * @param ui
+	 *            What URI was used to access this resource?
+	 * @return The description document.
+	 */
+	@GET
+	@Path(ROOT)
+	@Produces({ XML, JSON })
+	@Nonnull
+	AdminDescription getDescription(@Context UriInfo ui);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(ROOT)
+	Response optionsRoot();
+
+	/**
+	 * Get whether to allow new workflow runs to be created.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(ALLOW_NEW)
+	@Produces(PLAIN)
+	@Description("Whether to allow new workflow runs to be created.")
+	boolean getAllowNew();
+
+	/**
+	 * Set whether to allow new workflow runs to be created.
+	 * 
+	 * @param newValue
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(ALLOW_NEW)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Whether to allow new workflow runs to be created.")
+	boolean setAllowNew(boolean newValue);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(ALLOW_NEW)
+	@Description("Whether to allow new workflow runs to be created.")
+	Response optionsAllowNew();
+
+	/**
+	 * Get whether to log the workflows submitted.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(LOG_WFS)
+	@Produces(PLAIN)
+	@Description("Whether to log the workflows submitted.")
+	boolean getLogWorkflows();
+
+	/**
+	 * Set whether to log the workflows submitted.
+	 * 
+	 * @param logWorkflows
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(LOG_WFS)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Whether to log the workflows submitted.")
+	boolean setLogWorkflows(boolean logWorkflows);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(LOG_WFS)
+	@Description("Whether to log the workflows submitted.")
+	Response optionsLogWorkflows();
+
+	/**
+	 * Get whether to log the user-directed faults.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(LOG_EXN)
+	@Produces(PLAIN)
+	@Description("Whether to log the user-directed faults.")
+	boolean getLogFaults();
+
+	/**
+	 * Set whether to log the user-directed faults.
+	 * 
+	 * @param logFaults
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(LOG_EXN)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Whether to log the user-directed faults.")
+	boolean setLogFaults(boolean logFaults);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(LOG_EXN)
+	@Description("Whether to log the user-directed faults.")
+	Response optionsLogFaults();
+
+	/**
+	 * Get what file to dump usage records to.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(UR_FILE)
+	@Produces(PLAIN)
+	@Description("What file to dump usage records to.")
+	@Nonnull
+	String getURFile();
+
+	/**
+	 * Set what file to dump usage records to.
+	 * 
+	 * @param urFile
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(UR_FILE)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What file to dump usage records to.")
+	@Nonnull
+	String setURFile(@Nonnull String urFile);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(UR_FILE)
+	@Description("What file to dump usage records to.")
+	Response optionsURFile();
+
+	/**
+	 * The property for the number of times the service methods have been
+	 * invoked.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(INVOKES)
+	@Produces(PLAIN)
+	@Description("How many times have the service methods been invoked.")
+	int invokeCount();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(INVOKES)
+	@Description("How many times have the service methods been invoked.")
+	Response optionsInvokationCount();
+
+	/**
+	 * The property for the number of runs that are currently in existence.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(TOTAL_RUNS)
+	@Produces(PLAIN)
+	@Description("How many runs are currently in existence.")
+	int runCount();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(TOTAL_RUNS)
+	@Description("How many runs are currently in existence.")
+	Response optionsRunCount();
+
+	/**
+	 * The property for the number of runs that are currently running.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(OPERATING)
+	@Produces(PLAIN)
+	@Description("How many runs are currently actually running.")
+	int operatingCount();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(OPERATING)
+	@Description("How many runs are currently actually running.")
+	Response optionsOperatingCount();
+
+	/**
+	 * Get the full pathname of the RMI registry's JAR.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_JAR)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's custom RMI registry executable JAR file?")
+	@Nonnull
+	String getRegistryJar();
+
+	/**
+	 * Set the full pathname of the RMI registry's JAR.
+	 * 
+	 * @param registryJar
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_JAR)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's custom RMI registry executable JAR file?")
+	@Nonnull
+	String setRegistryJar(@Nonnull String registryJar);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_JAR)
+	@Description("What is the full pathname of the server's special custom RMI registry executable JAR file?")
+	Response optionsRegistryJar();
+
+	/**
+	 * Get the location of the RMI registry.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_HOST)
+	@Produces(PLAIN)
+	@Description("Where is the RMI registry?")
+	@Nonnull
+	String getRegistryHost();
+
+	/**
+	 * Set the location of the RMI registry.
+	 * 
+	 * @param registryHost
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_HOST)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Where is the RMI registry?")
+	@Nonnull
+	String setRegistryHost(@Nonnull String registryHost);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_HOST)
+	@Description("Where is the RMI registry?")
+	Response optionsRegistryHost();
+
+	/**
+	 * Get the port of the RMI registry.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_PORT)
+	@Produces(PLAIN)
+	@Description("On what port is the RMI registry?")
+	int getRegistryPort();
+
+	/**
+	 * Set the port of the RMI registry.
+	 * 
+	 * @param registryPort
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_PORT)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("On what port is the RMI registry?")
+	int setRegistryPort(int registryPort);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_PORT)
+	@Description("On what port is the RMI registry?")
+	Response optionsRegistryPort();
+
+	/**
+	 * Get the maximum number of simultaneous runs.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(RUN_LIMIT)
+	@Produces(PLAIN)
+	@Description("What is the maximum number of simultaneous runs?")
+	int getRunLimit();
+
+	/**
+	 * Set the maximum number of simultaneous runs.
+	 * 
+	 * @param runLimit
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(RUN_LIMIT)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the maximum number of simultaneous runs?")
+	int setRunLimit(int runLimit);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(RUN_LIMIT)
+	@Description("What is the maximum number of simultaneous runs?")
+	Response optionsRunLimit();
+
+	/**
+	 * Get the maximum number of simultaneous executing runs.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(OP_LIMIT)
+	@Produces(PLAIN)
+	@Description("What is the maximum number of simultaneous executing runs?")
+	int getOperatingLimit();
+
+	/**
+	 * Set the maximum number of simultaneous executing runs.
+	 * 
+	 * @param operatingLimit
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(OP_LIMIT)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the maximum number of simultaneous executing runs?")
+	int setOperatingLimit(int operatingLimit);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(OP_LIMIT)
+	@Description("What is the maximum number of simultaneous executing runs?")
+	Response optionsOperatingLimit();
+
+	/**
+	 * Get the default lifetime of workflow runs.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(LIFE)
+	@Produces(PLAIN)
+	@Description("What is the default lifetime of workflow runs, in seconds?")
+	int getDefaultLifetime();
+
+	/**
+	 * Set the default lifetime of workflow runs.
+	 * 
+	 * @param defaultLifetime
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(LIFE)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the default lifetime of workflow runs, in seconds?")
+	int setDefaultLifetime(int defaultLifetime);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(LIFE)
+	@Description("What is the default lifetime of workflow runs, in seconds?")
+	Response optionsDefaultLifetime();
+
+	/**
+	 * The property for the list of IDs of current runs.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(RUNS)
+	@Produces({ XML, JSON })
+	@Description("List the IDs of all current runs.")
+	StringList currentRuns();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(RUNS)
+	@Description("List the IDs of all current runs.")
+	Response optionsCurrentRuns();
+
+	/**
+	 * Get the Java binary to be used for execution of subprocesses.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(JAVA)
+	@Produces(PLAIN)
+	@Description("Which Java binary should be used for execution of subprocesses?")
+	@Nonnull
+	String getJavaBinary();
+
+	/**
+	 * Set the Java binary to be used for execution of subprocesses.
+	 * 
+	 * @param javaBinary
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(JAVA)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Which Java binary should be used for execution of subprocesses?")
+	@Nonnull
+	String setJavaBinary(@Nonnull String javaBinary);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(JAVA)
+	@Description("Which Java binary should be used for execution of subprocesses?")
+	Response optionsJavaBinary();
+
+	/**
+	 * Get the extra arguments to be supplied to Java subprocesses.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(ARGS)
+	@Produces({ XML, JSON })
+	@Description("What extra arguments should be supplied to Java subprocesses?")
+	@Nonnull
+	StringList getExtraArguments();
+
+	/**
+	 * Set the extra arguments to be supplied to Java subprocesses.
+	 * 
+	 * @param extraArguments
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(ARGS)
+	@Consumes(XML)
+	@Produces({ XML, JSON })
+	@Description("What extra arguments should be supplied to Java subprocesses?")
+	@Nonnull
+	StringList setExtraArguments(@Nonnull StringList extraArguments);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(ARGS)
+	@Description("What extra arguments should be supplied to Java subprocesses?")
+	Response optionsExtraArguments();
+
+	/**
+	 * Get the full pathname of the worker JAR file.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(JAR_WORKER)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
+	@Nonnull
+	String getServerWorkerJar();
+
+	/**
+	 * Set the full pathname of the worker JAR file.
+	 * 
+	 * @param serverWorkerJar
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(JAR_WORKER)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
+	@Nonnull
+	String setServerWorkerJar(@Nonnull String serverWorkerJar);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(JAR_WORKER)
+	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
+	Response optionsServerWorkerJar();
+
+	/**
+	 * Get the full pathname of the executeWorkflow.sh file.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(EXEC_WF)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
+	@Nonnull
+	String getExecuteWorkflowScript();
+
+	/**
+	 * Set the full pathname of the executeWorkflow.sh file.
+	 * 
+	 * @param executeWorkflowScript
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(EXEC_WF)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
+	@Nonnull
+	String setExecuteWorkflowScript(@Nonnull String executeWorkflowScript);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(EXEC_WF)
+	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
+	Response optionsExecuteWorkflowScript();
+
+	/**
+	 * Get the total duration of time to wait for the start of the forker
+	 * process.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_WAIT)
+	@Produces(PLAIN)
+	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
+	int getRegistrationWaitSeconds();
+
+	/**
+	 * Set the total duration of time to wait for the start of the forker
+	 * process.
+	 * 
+	 * @param registrationWaitSeconds
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_WAIT)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
+	int setRegistrationWaitSeconds(int registrationWaitSeconds);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_WAIT)
+	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
+	Response optionsRegistrationWaitSeconds();
+
+	/**
+	 * Get the interval between checks for registration of the forker process.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_POLL)
+	@Produces(PLAIN)
+	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
+	int getRegistrationPollMillis();
+
+	/**
+	 * Set the interval between checks for registration of the forker process.
+	 * 
+	 * @param registrationPollMillis
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_POLL)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
+	int setRegistrationPollMillis(int registrationPollMillis);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_POLL)
+	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
+	Response optionsRegistrationPollMillis();
+
+	/**
+	 * Get the full pathname of the file containing the impersonation
+	 * credentials for the forker process.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(PASSFILE)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
+	@Nonnull
+	String getRunasPasswordFile();
+
+	/**
+	 * Set the full pathname of the file containing the impersonation
+	 * credentials for the forker process.
+	 * 
+	 * @param runasPasswordFile
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(PASSFILE)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
+	@Nonnull
+	String setRunasPasswordFile(@Nonnull String runasPasswordFile);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(PASSFILE)
+	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
+	Response optionsRunasPasswordFile();
+
+	/**
+	 * Get the full pathname of the forker's JAR.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(JAR_FORKER)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
+	@Nonnull
+	String getServerForkerJar();
+
+	/**
+	 * Set the full pathname of the forker's JAR.
+	 * 
+	 * @param serverForkerJar
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(JAR_FORKER)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
+	@Nonnull
+	String setServerForkerJar(@Nonnull String serverForkerJar);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(JAR_FORKER)
+	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
+	Response optionsServerForkerJar();
+
+	/**
+	 * The property for the length of time it took to start the forker.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(STARTUP)
+	@Produces(PLAIN)
+	@Description("How long did it take for the back-end \"forker\" to set itself up, in seconds.")
+	int startupTime();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(STARTUP)
+	@Description("How long did it take for the back-end \"forker\" to set itself up, in seconds.")
+	Response optionsStartupTime();
+
+	/**
+	 * The property for the last exit code of the forker process.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(EXITCODE)
+	@Produces(PLAIN)
+	@Description("What was the last exit code of the \"forker\"? If null, no exit has ever been recorded.")
+	Integer lastExitCode();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(EXITCODE)
+	@Description("What was the last exit code of the \"forker\"? If null, no exit has ever been recorded.")
+	Response optionsLastExitCode();
+
+	/**
+	 * The property for the mapping of usernames to factory process handles.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(FACTORIES)
+	@Produces({ XML, JSON })
+	@Description("What is the mapping of local usernames to factory process RMI IDs?")
+	StringList factoryProcessMapping();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(FACTORIES)
+	@Description("What is the mapping of local usernames to factory process RMI IDs?")
+	Response optionsFactoryProcessMapping();
+
+	/**
+	 * The property for the list of usage records collected.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(URS)
+	@Produces(XML)
+	@Description("What is the list of usage records that have been collected?")
+	URList usageRecords();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(URS)
+	@Description("What is the list of usage records that have been collected?")
+	Response optionsUsageRecords();
+
+	/**
+	 * What are the current list of workflow URIs that may be started? Empty
+	 * means allow any, including user-supplied workflows.
+	 * 
+	 * @return List of URIs, encoded as strings.
+	 */
+	@GET
+	@Path(PERM_WF)
+	@Produces({ XML, JSON })
+	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
+	StringList getPermittedWorkflowURIs();
+
+	/** Do we turn on the generate provenance option by default? */
+	@GET
+	@Path(GEN_PROV)
+	@Produces(PLAIN)
+	@Description("Do we turn on the generate provenance option by default? (boolean)")
+	String getGenerateProvenance();
+
+	/** Do we turn on the generate provenance option by default? */
+	@PUT
+	@Path(GEN_PROV)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Do we turn on the generate provenance option by default? (boolean)")
+	String setGenerateProvenance(String newValue);
+
+	/** Do we turn on the generate provenance option by default? */
+	@OPTIONS
+	@Path(GEN_PROV)
+	@Description("Do we turn on the generate provenance option by default? (boolean)")
+	Response optionsGenerateProvenance();
+
+	/**
+	 * What are the current list of workflow URIs that may be started? Empty
+	 * means allow any, including user-supplied workflows.
+	 * 
+	 * @param permitted
+	 *            List of URIs, encoded as strings.
+	 * @return List of URIs, encoded as strings.
+	 */
+	@PUT
+	@Path(PERM_WF)
+	@Consumes(XML)
+	@Produces({ XML, JSON })
+	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
+	StringList setPermittedWorkflowURIs(@Nonnull StringList permitted);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(PERM_WF)
+	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
+	Response optionsPermittedWorkflowURIs();
+
+	@GET
+	@Path(USERS)
+	@Produces({ XML, JSON })
+	@Description("What users are known to the server?")
+	UserList users(@Context UriInfo ui);
+
+	@GET
+	@Path(USER)
+	@Produces({ XML, JSON })
+	@Description("What do we know about a particular user?")
+	UserDesc user(@PathParam("id") String username);
+
+	@POST
+	@Path(USERS)
+	@Consumes(XML)
+	@Description("Create a user.")
+	Response useradd(UserDesc userdesc, @Nonnull @Context UriInfo ui);
+
+	@PUT
+	@Path(USER)
+	@Produces({ XML, JSON })
+	@Consumes(XML)
+	@Description("Update a user.")
+	UserDesc userset(@PathParam("id") String username, UserDesc userdesc);
+
+	@DELETE
+	@Path(USER)
+	@Produces({ XML, JSON })
+	@Description("What do we know about a particular user?")
+	Response userdel(@PathParam("id") String username);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(USERS)
+	@Description("What users are known to the server?")
+	Response optionsUsers();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(USER)
+	@Description("What do we know about a particular user?")
+	Response optionsUser(@PathParam("id") String username);
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	/**
+	 * The description of what properties are supported by the administration
+	 * interface.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "description")
+	@XmlType(name = "Description")
+	public static class AdminDescription extends VersionedElement {
+		public Uri allowNew;
+		public Uri logWorkflows;
+		public Uri logFaults;
+		public Uri usageRecordDumpFile;
+		public Uri invokationCount;
+		public Uri runCount;
+		public Uri registryHost;
+		public Uri registryPort;
+		public Uri runLimit;
+		public Uri defaultLifetime;
+		public Uri currentRuns;
+		public Uri javaBinary;
+		public Uri extraArguments;
+		public Uri serverWorkerJar;
+		public Uri serverForkerJar;
+		public Uri executeWorkflowScript;
+		public Uri registrationWaitSeconds;
+		public Uri registrationPollMillis;
+		public Uri runasPasswordFile;
+		public Uri startupTime;
+		public Uri lastExitCode;
+		public Uri factoryProcessMapping;
+		public Uri usageRecords;
+		public Uri users;
+		public Uri operatingLimit;
+		public Uri operatingCount;
+		public Uri permittedWorkflowURIs;
+		public Uri generateProvenance;
+
+		public AdminDescription() {
+		}
+
+		public AdminDescription(UriInfo ui) {
+			allowNew = new Uri(ui, ALLOW_NEW);
+			logWorkflows = new Uri(ui, LOG_WFS);
+			logFaults = new Uri(ui, LOG_EXN);
+			usageRecordDumpFile = new Uri(ui, UR_FILE);
+			invokationCount = new Uri(ui, INVOKES);
+			runCount = new Uri(ui, TOTAL_RUNS);
+			registryHost = new Uri(ui, REG_HOST);
+			registryPort = new Uri(ui, REG_PORT);
+			runLimit = new Uri(ui, RUN_LIMIT);
+			defaultLifetime = new Uri(ui, LIFE);
+			currentRuns = new Uri(ui, RUNS);
+			javaBinary = new Uri(ui, JAVA);
+			extraArguments = new Uri(ui, ARGS);
+			serverWorkerJar = new Uri(ui, JAR_WORKER);
+			serverForkerJar = new Uri(ui, JAR_FORKER);
+			executeWorkflowScript = new Uri(ui, EXEC_WF);
+			registrationWaitSeconds = new Uri(ui, REG_WAIT);
+			registrationPollMillis = new Uri(ui, REG_POLL);
+			runasPasswordFile = new Uri(ui, PASSFILE);
+			startupTime = new Uri(ui, STARTUP);
+			lastExitCode = new Uri(ui, EXITCODE);
+			factoryProcessMapping = new Uri(ui, FACTORIES);
+			usageRecords = new Uri(ui, URS);
+			users = new Uri(ui, USERS);
+			operatingLimit = new Uri(ui, OP_LIMIT);
+			operatingCount = new Uri(ui, OPERATING);
+			permittedWorkflowURIs = new Uri(ui, PERM_WF);
+			generateProvenance = new Uri(ui, GEN_PROV);
+		}
+	}
+
+	/**
+	 * A list of strings, as XML.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "stringList")
+	@XmlType(name = "StringList")
+	public static class StringList {
+		@XmlElement
+		public List<String> string = new ArrayList<>();
+	}
+
+	/**
+	 * A list of users, as XML.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "userList")
+	@XmlType(name = "UserList")
+	public static class UserList {
+		@XmlElement
+		public List<URI> user = new ArrayList<>();
+	}
+
+	@XmlRootElement(name = "userDesc")
+	@XmlType(name = "UserDesc")
+	public static class UserDesc {
+		@XmlElement
+		public String username;
+		@XmlElement
+		public String password;
+		@XmlElement
+		public String localUserId;
+		@XmlElement
+		public Boolean enabled;
+		@XmlElement
+		public Boolean admin;
+	}
+
+	/**
+	 * A list of usage records, as XML.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "usageRecordList")
+	@XmlType(name = "UsageRecords")
+	public static class URList {
+		@XmlElement
+		public List<JobUsageRecord> usageRecord;
+	}
+}
+
+interface Paths {
+	static final String ROOT = "/";
+	static final String ALLOW_NEW = "allowNew";
+	static final String LOG_WFS = "logWorkflows";
+	static final String LOG_EXN = "logFaults";
+	static final String UR_FILE = "usageRecordDumpFile";
+	static final String INVOKES = "invokationCount";
+	static final String TOTAL_RUNS = "runCount";
+	static final String OPERATING = "operatingCount";
+	static final String REG_HOST = "registryHost";
+	static final String REG_PORT = "registryPort";
+	static final String REG_JAR = "registryJar";
+	static final String RUN_LIMIT = "runLimit";
+	static final String OP_LIMIT = "operatingLimit";
+	static final String LIFE = "defaultLifetime";
+	static final String RUNS = "currentRuns";
+	static final String JAVA = "javaBinary";
+	static final String ARGS = "extraArguments";
+	static final String JAR_WORKER = "serverWorkerJar";
+	static final String JAR_FORKER = "serverForkerJar";
+	static final String EXEC_WF = "executeWorkflowScript";
+	static final String REG_WAIT = "registrationWaitSeconds";
+	static final String REG_POLL = "registrationPollMillis";
+	static final String PASSFILE = "runasPasswordFile";
+	static final String STARTUP = "startupTime";
+	static final String EXITCODE = "lastExitCode";
+	static final String FACTORIES = "factoryProcessMapping";
+	static final String URS = "usageRecords";
+	static final String PERM_WF = "permittedWorkflowURIs";
+	static final String GEN_PROV = "generateProvenance";
+	static final String USERS = "users";
+	static final String USER = USERS + "/{id}";
+}
+
+interface Types {
+	static final String PLAIN = "text/plain";
+	static final String XML = "application/xml";
+	static final String JSON = "application/json";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/AdminBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/AdminBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/AdminBean.java
new file mode 100644
index 0000000..0233cd5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/AdminBean.java
@@ -0,0 +1,807 @@
+/*
+ */
+package org.taverna.server.master.admin;
+/*
+ * 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.
+ */
+
+import static java.util.Arrays.asList;
+import static java.util.UUID.randomUUID;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.Response.noContent;
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+import static org.taverna.server.master.common.Roles.ADMIN;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.ManagementModel;
+import org.taverna.server.master.exceptions.GeneralFailureException;
+import org.taverna.server.master.factories.ConfigurableRunFactory;
+import org.taverna.server.master.identity.User;
+import org.taverna.server.master.identity.UserStoreAPI;
+import org.taverna.server.master.usage.UsageRecordRecorder;
+import org.taverna.server.master.utils.InvocationCounter;
+import org.taverna.server.master.worker.RunDBSupport;
+import org.taverna.server.master.worker.WorkerModel;
+
+/**
+ * The administration interface to Taverna Server.
+ * 
+ * @author Donal Fellows
+ */
+public class AdminBean implements Admin {
+	@Required
+	public void setState(ManagementModel state) {
+		this.state = state;
+	}
+
+	@Required
+	public void setCounter(InvocationCounter counter) {
+		this.counter = counter;
+	}
+
+	@Required
+	public void setRunDB(RunDBSupport runDB) {
+		this.runDB = runDB;
+	}
+
+	@Required
+	public void setFactory(ConfigurableRunFactory factory) {
+		this.factory = factory;
+	}
+
+	@Required
+	public void setUsageRecords(UsageRecordRecorder usageRecords) {
+		this.usageRecords = usageRecords;
+	}
+
+	@Required
+	public void setUserStore(UserStoreAPI userStore) {
+		this.userStore = userStore;
+	}
+
+	@Required
+	public void setLocalWorkerModel(WorkerModel worker) {
+		localWorker = worker;
+	}
+
+	public void setAdminHtmlFile(String filename) {
+		this.adminHtmlFile = filename;
+	}
+
+	public void setResourceRoot(String root) {
+		this.resourceRoot = root;
+	}
+
+	protected byte[] getResource(String name) throws IOException {
+		if (AdminBean.class.getResource(name) == null)
+			throw new FileNotFoundException(name);
+		return IOUtils.toByteArray(AdminBean.class.getResourceAsStream(name));
+	}
+
+	private ManagementModel state;
+	private InvocationCounter counter;
+	private RunDBSupport runDB;
+	private ConfigurableRunFactory factory;
+	private UsageRecordRecorder usageRecords;
+	private UserStoreAPI userStore;
+	private WorkerModel localWorker;
+	private String adminHtmlFile = "/admin.html";
+	private String resourceRoot = "/static/";
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response getUserInterface() throws IOException {
+		return Response.ok(getResource(adminHtmlFile), "text/html").build();
+	}
+
+	@Override
+	@RolesAllowed(ADMIN)
+	public Response getStaticResource(String file) throws IOException {
+		if (file.matches("^[-_.a-zA-Z0-9]+$")) {
+			String type = "application/octet-stream";
+			if (file.endsWith(".html"))
+				type = "text/html";
+			else if (file.endsWith(".js"))
+				type = "text/javascript";
+			else if (file.endsWith(".jpg"))
+				type = "image/jpeg";
+			else if (file.endsWith(".gif"))
+				type = "image/gif";
+			else if (file.endsWith(".png"))
+				type = "image/png";
+			else if (file.endsWith(".svg"))
+				type = "image/svg+xml";
+			else if (file.endsWith(".css"))
+				type = "text/css";
+			try {
+				return Response.ok(getResource(resourceRoot + file), type)
+						.build();
+			} catch (IOException e) {
+				// ignore; we just treat as 404
+			}
+		}
+		return Response.status(NOT_FOUND).entity("no such resource").build();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public AdminDescription getDescription(UriInfo ui) {
+		return new AdminDescription(ui);
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRoot() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean getAllowNew() {
+		return state.getAllowNewWorkflowRuns();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean setAllowNew(boolean newValue) {
+		state.setAllowNewWorkflowRuns(newValue);
+		return state.getAllowNewWorkflowRuns();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsAllowNew() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean getLogWorkflows() {
+		return state.getLogIncomingWorkflows();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean setLogWorkflows(boolean newValue) {
+		state.setLogIncomingWorkflows(newValue);
+		return state.getLogIncomingWorkflows();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsLogWorkflows() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean getLogFaults() {
+		return state.getLogOutgoingExceptions();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean setLogFaults(boolean newValue) {
+		state.setLogOutgoingExceptions(newValue);
+		return state.getLogOutgoingExceptions();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsLogFaults() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getURFile() {
+		return state.getUsageRecordLogFile();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setURFile(String newValue) {
+		state.setUsageRecordLogFile(newValue);
+		return state.getUsageRecordLogFile();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsURFile() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int invokeCount() {
+		return counter.getCount();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsInvokationCount() {
+		return opt();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int runCount() {
+		return runDB.countRuns();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRunCount() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getRegistryHost() {
+		return factory.getRegistryHost();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setRegistryHost(String newValue) {
+		factory.setRegistryHost(newValue);
+		return factory.getRegistryHost();
+	}
+
+	@Override
+	public Response optionsRegistryHost() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getRegistryPort() {
+		return factory.getRegistryPort();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setRegistryPort(int newValue) {
+		factory.setRegistryPort(newValue);
+		return factory.getRegistryPort();
+	}
+
+	@Override
+	public Response optionsRegistryPort() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getRegistryJar() {
+		return factory.getRmiRegistryJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setRegistryJar(String registryJar) {
+		factory.setRmiRegistryJar(registryJar);
+		return factory.getRmiRegistryJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRegistryJar() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getRunLimit() {
+		return factory.getMaxRuns();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setRunLimit(int newValue) {
+		factory.setMaxRuns(newValue);
+		return factory.getMaxRuns();
+	}
+
+	@Override
+	public Response optionsRunLimit() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getDefaultLifetime() {
+		return factory.getDefaultLifetime();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setDefaultLifetime(int newValue) {
+		factory.setDefaultLifetime(newValue);
+		return factory.getDefaultLifetime();
+	}
+
+	@Override
+	public Response optionsDefaultLifetime() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList currentRuns() {
+		StringList result = new StringList();
+		result.string = runDB.listRunNames();
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsCurrentRuns() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getJavaBinary() {
+		return factory.getJavaBinary();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setJavaBinary(String newValue) {
+		factory.setJavaBinary(newValue);
+		return factory.getJavaBinary();
+	}
+
+	@Override
+	public Response optionsJavaBinary() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList getExtraArguments() {
+		String[] xargs = factory.getExtraArguments();
+		StringList result = new StringList();
+		result.string = asList(xargs == null ? new String[0] : xargs);
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList setExtraArguments(StringList newValue) {
+		if (newValue == null || newValue.string == null)
+			factory.setExtraArguments(new String[0]);
+		else
+			factory.setExtraArguments(newValue.string
+					.toArray(new String[newValue.string.size()]));
+		StringList result = new StringList();
+		result.string = asList(factory.getExtraArguments());
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsExtraArguments() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getServerWorkerJar() {
+		return factory.getServerWorkerJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setServerWorkerJar(String newValue) {
+		factory.setServerWorkerJar(newValue);
+		return factory.getServerWorkerJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsServerWorkerJar() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getExecuteWorkflowScript() {
+		return factory.getExecuteWorkflowScript();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setExecuteWorkflowScript(String newValue) {
+		factory.setExecuteWorkflowScript(newValue);
+		return factory.getExecuteWorkflowScript();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsExecuteWorkflowScript() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getRegistrationWaitSeconds() {
+		return factory.getWaitSeconds();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setRegistrationWaitSeconds(int newValue) {
+		factory.setWaitSeconds(newValue);
+		return factory.getWaitSeconds();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRegistrationWaitSeconds() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getRegistrationPollMillis() {
+		return factory.getSleepTime();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setRegistrationPollMillis(int newValue) {
+		factory.setSleepTime(newValue);
+		return factory.getSleepTime();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRegistrationPollMillis() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getRunasPasswordFile() {
+		return factory.getPasswordFile();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setRunasPasswordFile(String newValue) {
+		factory.setPasswordFile(newValue);
+		return factory.getPasswordFile();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRunasPasswordFile() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getServerForkerJar() {
+		return factory.getServerForkerJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setServerForkerJar(String newValue) {
+		factory.setServerForkerJar(newValue);
+		return factory.getServerForkerJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsServerForkerJar() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int startupTime() {
+		return factory.getLastStartupCheckCount();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsStartupTime() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Integer lastExitCode() {
+		return factory.getLastExitCode();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsLastExitCode() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList factoryProcessMapping() {
+		StringList result = new StringList();
+		result.string = asList(factory.getFactoryProcessMapping());
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsFactoryProcessMapping() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public URList usageRecords() {
+		URList result = new URList();
+		result.usageRecord = usageRecords.getUsageRecords();
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsUsageRecords() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public UserList users(UriInfo ui) {
+		UserList ul = new UserList();
+		UriBuilder ub = secure(ui).path("{id}");
+		for (String user : userStore.getUserNames())
+			ul.user.add(ub.build(user));
+		return ul;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsUsers() {
+		return opt("POST");
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public UserDesc user(String username) {
+		UserDesc desc = new UserDesc();
+		User u = userStore.getUser(username);
+		desc.username = u.getUsername();
+		desc.localUserId = u.getLocalUsername();
+		desc.admin = u.isAdmin();
+		desc.enabled = u.isEnabled();
+		return desc;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsUser(String username) {
+		return opt("PUT", "DELETE");
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response useradd(UserDesc userdesc, UriInfo ui) {
+		if (userdesc.username == null)
+			throw new IllegalArgumentException("no user name supplied");
+		if (userdesc.password == null)
+			userdesc.password = randomUUID().toString();
+		userStore.addUser(userdesc.username, userdesc.password, false);
+		if (userdesc.localUserId != null)
+			userStore.setUserLocalUser(userdesc.username, userdesc.localUserId);
+		if (userdesc.admin != null && userdesc.admin)
+			userStore.setUserAdmin(userdesc.username, true);
+		if (userdesc.enabled != null && userdesc.enabled)
+			userStore.setUserEnabled(userdesc.username, true);
+		return created(secure(ui).path("{id}").build(userdesc.username))
+				.build();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public UserDesc userset(String username, UserDesc userdesc) {
+		if (userdesc.password != null)
+			userStore.setUserPassword(username, userdesc.password);
+		if (userdesc.localUserId != null)
+			userStore.setUserLocalUser(username, userdesc.localUserId);
+		if (userdesc.admin != null)
+			userStore.setUserAdmin(username, userdesc.admin);
+		if (userdesc.enabled != null)
+			userStore.setUserEnabled(username, userdesc.enabled);
+		userdesc = null; // Stop reuse!
+
+		UserDesc desc = new UserDesc();
+		User u = userStore.getUser(username);
+		desc.username = u.getUsername();
+		desc.localUserId = u.getLocalUsername();
+		desc.admin = u.isAdmin();
+		desc.enabled = u.isEnabled();
+		return desc;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response userdel(String username) {
+		userStore.deleteUser(username);
+		return noContent().build();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int operatingCount() {
+		try {
+			return factory.getOperatingCount();
+		} catch (Exception e) {
+			throw new GeneralFailureException(e);
+		}
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsOperatingCount() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getOperatingLimit() {
+		return factory.getOperatingLimit();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setOperatingLimit(int operatingLimit) {
+		factory.setOperatingLimit(operatingLimit);
+		return factory.getOperatingLimit();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsOperatingLimit() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList getPermittedWorkflowURIs() {
+		StringList sl = new StringList();
+		List<URI> uris = localWorker.getPermittedWorkflowURIs();
+		if (uris != null)
+			for (URI uri : uris)
+				sl.string.add(uri.toString());
+		return sl;
+	}
+
+	private static final URI myExp = URI.create("http://www.myexperment.org/");
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList setPermittedWorkflowURIs(StringList permitted) {
+		List<URI> uris = new ArrayList<>();
+		for (String uri : permitted.string)
+			try {
+				uris.add(myExp.resolve(uri));
+			} catch (Exception e) {
+				// Ignore
+			}
+		localWorker.setPermittedWorkflowURIs(uris);
+		return getPermittedWorkflowURIs();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsPermittedWorkflowURIs() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getGenerateProvenance() {
+		return Boolean.toString(localWorker.getGenerateProvenance());
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setGenerateProvenance(String newValue) {
+		boolean b = Boolean.parseBoolean(newValue);
+		localWorker.setGenerateProvenance(b);
+		return Boolean.toString(localWorker.getGenerateProvenance());
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsGenerateProvenance() {
+		return opt("PUT");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/package-info.java
new file mode 100644
index 0000000..0a4174e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/admin/package-info.java
@@ -0,0 +1,46 @@
+/*
+ */
+/**
+ * This package contains the RESTful administration interface to Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = ADMIN, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN),
+		@XmlNs(prefix = "ur", namespaceURI = UR),
+		@XmlNs(prefix = "ds", namespaceURI = XSIG) })
+package org.taverna.server.master.admin;
+/*
+ * 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.
+ */
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.UR;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.master.common.Namespaces.XSIG;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+



[17/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java
deleted file mode 100644
index 03c0c8b..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java
+++ /dev/null
@@ -1,1113 +0,0 @@
-/*
- */
-package org.taverna.server.master.admin;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.admin.Paths.ALLOW_NEW;
-import static org.taverna.server.master.admin.Paths.ARGS;
-import static org.taverna.server.master.admin.Paths.EXEC_WF;
-import static org.taverna.server.master.admin.Paths.EXITCODE;
-import static org.taverna.server.master.admin.Paths.FACTORIES;
-import static org.taverna.server.master.admin.Paths.GEN_PROV;
-import static org.taverna.server.master.admin.Paths.INVOKES;
-import static org.taverna.server.master.admin.Paths.JAR_FORKER;
-import static org.taverna.server.master.admin.Paths.JAR_WORKER;
-import static org.taverna.server.master.admin.Paths.JAVA;
-import static org.taverna.server.master.admin.Paths.LIFE;
-import static org.taverna.server.master.admin.Paths.LOG_EXN;
-import static org.taverna.server.master.admin.Paths.LOG_WFS;
-import static org.taverna.server.master.admin.Paths.OPERATING;
-import static org.taverna.server.master.admin.Paths.OP_LIMIT;
-import static org.taverna.server.master.admin.Paths.PASSFILE;
-import static org.taverna.server.master.admin.Paths.PERM_WF;
-import static org.taverna.server.master.admin.Paths.REG_HOST;
-import static org.taverna.server.master.admin.Paths.REG_JAR;
-import static org.taverna.server.master.admin.Paths.REG_POLL;
-import static org.taverna.server.master.admin.Paths.REG_PORT;
-import static org.taverna.server.master.admin.Paths.REG_WAIT;
-import static org.taverna.server.master.admin.Paths.ROOT;
-import static org.taverna.server.master.admin.Paths.RUNS;
-import static org.taverna.server.master.admin.Paths.RUN_LIMIT;
-import static org.taverna.server.master.admin.Paths.STARTUP;
-import static org.taverna.server.master.admin.Paths.TOTAL_RUNS;
-import static org.taverna.server.master.admin.Paths.URS;
-import static org.taverna.server.master.admin.Paths.UR_FILE;
-import static org.taverna.server.master.admin.Paths.USER;
-import static org.taverna.server.master.admin.Paths.USERS;
-import static org.taverna.server.master.admin.Types.JSON;
-import static org.taverna.server.master.admin.Types.PLAIN;
-import static org.taverna.server.master.admin.Types.XML;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.apache.taverna.server.usagerecord.JobUsageRecord;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-
-/**
- * The administration interface for Taverna Server.
- * 
- * @author Donal Fellows
- */
-@Description("Administration interface for Taverna Server.")
-public interface Admin {
-	/**
-	 * Get a simple administration user interface.
-	 * 
-	 * @return The description document in a response.
-	 * @throws IOException
-	 */
-	@GET
-	@Path(ROOT)
-	@Produces("text/html")
-	@Nonnull
-	Response getUserInterface() throws IOException;
-
-	/**
-	 * Gets support resources for the administration user interface.
-	 * 
-	 * @param file
-	 *            The name of the static resource to provide.
-	 * @return The requested document in a response.
-	 * @throws IOException
-	 */
-	@GET
-	@Path("static/{file}")
-	@Produces("*/*")
-	Response getStaticResource(@PathParam("file") String file)
-			throws IOException;
-
-	/**
-	 * Get a description of the administration interface.
-	 * 
-	 * @param ui
-	 *            What URI was used to access this resource?
-	 * @return The description document.
-	 */
-	@GET
-	@Path(ROOT)
-	@Produces({ XML, JSON })
-	@Nonnull
-	AdminDescription getDescription(@Context UriInfo ui);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(ROOT)
-	Response optionsRoot();
-
-	/**
-	 * Get whether to allow new workflow runs to be created.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(ALLOW_NEW)
-	@Produces(PLAIN)
-	@Description("Whether to allow new workflow runs to be created.")
-	boolean getAllowNew();
-
-	/**
-	 * Set whether to allow new workflow runs to be created.
-	 * 
-	 * @param newValue
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(ALLOW_NEW)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Whether to allow new workflow runs to be created.")
-	boolean setAllowNew(boolean newValue);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(ALLOW_NEW)
-	@Description("Whether to allow new workflow runs to be created.")
-	Response optionsAllowNew();
-
-	/**
-	 * Get whether to log the workflows submitted.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(LOG_WFS)
-	@Produces(PLAIN)
-	@Description("Whether to log the workflows submitted.")
-	boolean getLogWorkflows();
-
-	/**
-	 * Set whether to log the workflows submitted.
-	 * 
-	 * @param logWorkflows
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(LOG_WFS)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Whether to log the workflows submitted.")
-	boolean setLogWorkflows(boolean logWorkflows);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(LOG_WFS)
-	@Description("Whether to log the workflows submitted.")
-	Response optionsLogWorkflows();
-
-	/**
-	 * Get whether to log the user-directed faults.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(LOG_EXN)
-	@Produces(PLAIN)
-	@Description("Whether to log the user-directed faults.")
-	boolean getLogFaults();
-
-	/**
-	 * Set whether to log the user-directed faults.
-	 * 
-	 * @param logFaults
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(LOG_EXN)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Whether to log the user-directed faults.")
-	boolean setLogFaults(boolean logFaults);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(LOG_EXN)
-	@Description("Whether to log the user-directed faults.")
-	Response optionsLogFaults();
-
-	/**
-	 * Get what file to dump usage records to.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(UR_FILE)
-	@Produces(PLAIN)
-	@Description("What file to dump usage records to.")
-	@Nonnull
-	String getURFile();
-
-	/**
-	 * Set what file to dump usage records to.
-	 * 
-	 * @param urFile
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(UR_FILE)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What file to dump usage records to.")
-	@Nonnull
-	String setURFile(@Nonnull String urFile);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(UR_FILE)
-	@Description("What file to dump usage records to.")
-	Response optionsURFile();
-
-	/**
-	 * The property for the number of times the service methods have been
-	 * invoked.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(INVOKES)
-	@Produces(PLAIN)
-	@Description("How many times have the service methods been invoked.")
-	int invokeCount();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(INVOKES)
-	@Description("How many times have the service methods been invoked.")
-	Response optionsInvokationCount();
-
-	/**
-	 * The property for the number of runs that are currently in existence.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(TOTAL_RUNS)
-	@Produces(PLAIN)
-	@Description("How many runs are currently in existence.")
-	int runCount();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(TOTAL_RUNS)
-	@Description("How many runs are currently in existence.")
-	Response optionsRunCount();
-
-	/**
-	 * The property for the number of runs that are currently running.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(OPERATING)
-	@Produces(PLAIN)
-	@Description("How many runs are currently actually running.")
-	int operatingCount();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(OPERATING)
-	@Description("How many runs are currently actually running.")
-	Response optionsOperatingCount();
-
-	/**
-	 * Get the full pathname of the RMI registry's JAR.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_JAR)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's custom RMI registry executable JAR file?")
-	@Nonnull
-	String getRegistryJar();
-
-	/**
-	 * Set the full pathname of the RMI registry's JAR.
-	 * 
-	 * @param registryJar
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_JAR)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's custom RMI registry executable JAR file?")
-	@Nonnull
-	String setRegistryJar(@Nonnull String registryJar);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_JAR)
-	@Description("What is the full pathname of the server's special custom RMI registry executable JAR file?")
-	Response optionsRegistryJar();
-
-	/**
-	 * Get the location of the RMI registry.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_HOST)
-	@Produces(PLAIN)
-	@Description("Where is the RMI registry?")
-	@Nonnull
-	String getRegistryHost();
-
-	/**
-	 * Set the location of the RMI registry.
-	 * 
-	 * @param registryHost
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_HOST)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Where is the RMI registry?")
-	@Nonnull
-	String setRegistryHost(@Nonnull String registryHost);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_HOST)
-	@Description("Where is the RMI registry?")
-	Response optionsRegistryHost();
-
-	/**
-	 * Get the port of the RMI registry.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_PORT)
-	@Produces(PLAIN)
-	@Description("On what port is the RMI registry?")
-	int getRegistryPort();
-
-	/**
-	 * Set the port of the RMI registry.
-	 * 
-	 * @param registryPort
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_PORT)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("On what port is the RMI registry?")
-	int setRegistryPort(int registryPort);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_PORT)
-	@Description("On what port is the RMI registry?")
-	Response optionsRegistryPort();
-
-	/**
-	 * Get the maximum number of simultaneous runs.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(RUN_LIMIT)
-	@Produces(PLAIN)
-	@Description("What is the maximum number of simultaneous runs?")
-	int getRunLimit();
-
-	/**
-	 * Set the maximum number of simultaneous runs.
-	 * 
-	 * @param runLimit
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(RUN_LIMIT)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the maximum number of simultaneous runs?")
-	int setRunLimit(int runLimit);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(RUN_LIMIT)
-	@Description("What is the maximum number of simultaneous runs?")
-	Response optionsRunLimit();
-
-	/**
-	 * Get the maximum number of simultaneous executing runs.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(OP_LIMIT)
-	@Produces(PLAIN)
-	@Description("What is the maximum number of simultaneous executing runs?")
-	int getOperatingLimit();
-
-	/**
-	 * Set the maximum number of simultaneous executing runs.
-	 * 
-	 * @param operatingLimit
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(OP_LIMIT)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the maximum number of simultaneous executing runs?")
-	int setOperatingLimit(int operatingLimit);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(OP_LIMIT)
-	@Description("What is the maximum number of simultaneous executing runs?")
-	Response optionsOperatingLimit();
-
-	/**
-	 * Get the default lifetime of workflow runs.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(LIFE)
-	@Produces(PLAIN)
-	@Description("What is the default lifetime of workflow runs, in seconds?")
-	int getDefaultLifetime();
-
-	/**
-	 * Set the default lifetime of workflow runs.
-	 * 
-	 * @param defaultLifetime
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(LIFE)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the default lifetime of workflow runs, in seconds?")
-	int setDefaultLifetime(int defaultLifetime);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(LIFE)
-	@Description("What is the default lifetime of workflow runs, in seconds?")
-	Response optionsDefaultLifetime();
-
-	/**
-	 * The property for the list of IDs of current runs.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(RUNS)
-	@Produces({ XML, JSON })
-	@Description("List the IDs of all current runs.")
-	StringList currentRuns();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(RUNS)
-	@Description("List the IDs of all current runs.")
-	Response optionsCurrentRuns();
-
-	/**
-	 * Get the Java binary to be used for execution of subprocesses.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(JAVA)
-	@Produces(PLAIN)
-	@Description("Which Java binary should be used for execution of subprocesses?")
-	@Nonnull
-	String getJavaBinary();
-
-	/**
-	 * Set the Java binary to be used for execution of subprocesses.
-	 * 
-	 * @param javaBinary
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(JAVA)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Which Java binary should be used for execution of subprocesses?")
-	@Nonnull
-	String setJavaBinary(@Nonnull String javaBinary);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(JAVA)
-	@Description("Which Java binary should be used for execution of subprocesses?")
-	Response optionsJavaBinary();
-
-	/**
-	 * Get the extra arguments to be supplied to Java subprocesses.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(ARGS)
-	@Produces({ XML, JSON })
-	@Description("What extra arguments should be supplied to Java subprocesses?")
-	@Nonnull
-	StringList getExtraArguments();
-
-	/**
-	 * Set the extra arguments to be supplied to Java subprocesses.
-	 * 
-	 * @param extraArguments
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(ARGS)
-	@Consumes(XML)
-	@Produces({ XML, JSON })
-	@Description("What extra arguments should be supplied to Java subprocesses?")
-	@Nonnull
-	StringList setExtraArguments(@Nonnull StringList extraArguments);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(ARGS)
-	@Description("What extra arguments should be supplied to Java subprocesses?")
-	Response optionsExtraArguments();
-
-	/**
-	 * Get the full pathname of the worker JAR file.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(JAR_WORKER)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
-	@Nonnull
-	String getServerWorkerJar();
-
-	/**
-	 * Set the full pathname of the worker JAR file.
-	 * 
-	 * @param serverWorkerJar
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(JAR_WORKER)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
-	@Nonnull
-	String setServerWorkerJar(@Nonnull String serverWorkerJar);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(JAR_WORKER)
-	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
-	Response optionsServerWorkerJar();
-
-	/**
-	 * Get the full pathname of the executeWorkflow.sh file.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(EXEC_WF)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
-	@Nonnull
-	String getExecuteWorkflowScript();
-
-	/**
-	 * Set the full pathname of the executeWorkflow.sh file.
-	 * 
-	 * @param executeWorkflowScript
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(EXEC_WF)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
-	@Nonnull
-	String setExecuteWorkflowScript(@Nonnull String executeWorkflowScript);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(EXEC_WF)
-	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
-	Response optionsExecuteWorkflowScript();
-
-	/**
-	 * Get the total duration of time to wait for the start of the forker
-	 * process.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_WAIT)
-	@Produces(PLAIN)
-	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
-	int getRegistrationWaitSeconds();
-
-	/**
-	 * Set the total duration of time to wait for the start of the forker
-	 * process.
-	 * 
-	 * @param registrationWaitSeconds
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_WAIT)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
-	int setRegistrationWaitSeconds(int registrationWaitSeconds);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_WAIT)
-	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
-	Response optionsRegistrationWaitSeconds();
-
-	/**
-	 * Get the interval between checks for registration of the forker process.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_POLL)
-	@Produces(PLAIN)
-	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
-	int getRegistrationPollMillis();
-
-	/**
-	 * Set the interval between checks for registration of the forker process.
-	 * 
-	 * @param registrationPollMillis
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_POLL)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
-	int setRegistrationPollMillis(int registrationPollMillis);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_POLL)
-	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
-	Response optionsRegistrationPollMillis();
-
-	/**
-	 * Get the full pathname of the file containing the impersonation
-	 * credentials for the forker process.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(PASSFILE)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
-	@Nonnull
-	String getRunasPasswordFile();
-
-	/**
-	 * Set the full pathname of the file containing the impersonation
-	 * credentials for the forker process.
-	 * 
-	 * @param runasPasswordFile
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(PASSFILE)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
-	@Nonnull
-	String setRunasPasswordFile(@Nonnull String runasPasswordFile);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(PASSFILE)
-	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
-	Response optionsRunasPasswordFile();
-
-	/**
-	 * Get the full pathname of the forker's JAR.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(JAR_FORKER)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
-	@Nonnull
-	String getServerForkerJar();
-
-	/**
-	 * Set the full pathname of the forker's JAR.
-	 * 
-	 * @param serverForkerJar
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(JAR_FORKER)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
-	@Nonnull
-	String setServerForkerJar(@Nonnull String serverForkerJar);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(JAR_FORKER)
-	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
-	Response optionsServerForkerJar();
-
-	/**
-	 * The property for the length of time it took to start the forker.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(STARTUP)
-	@Produces(PLAIN)
-	@Description("How long did it take for the back-end \"forker\" to set itself up, in seconds.")
-	int startupTime();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(STARTUP)
-	@Description("How long did it take for the back-end \"forker\" to set itself up, in seconds.")
-	Response optionsStartupTime();
-
-	/**
-	 * The property for the last exit code of the forker process.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(EXITCODE)
-	@Produces(PLAIN)
-	@Description("What was the last exit code of the \"forker\"? If null, no exit has ever been recorded.")
-	Integer lastExitCode();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(EXITCODE)
-	@Description("What was the last exit code of the \"forker\"? If null, no exit has ever been recorded.")
-	Response optionsLastExitCode();
-
-	/**
-	 * The property for the mapping of usernames to factory process handles.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(FACTORIES)
-	@Produces({ XML, JSON })
-	@Description("What is the mapping of local usernames to factory process RMI IDs?")
-	StringList factoryProcessMapping();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(FACTORIES)
-	@Description("What is the mapping of local usernames to factory process RMI IDs?")
-	Response optionsFactoryProcessMapping();
-
-	/**
-	 * The property for the list of usage records collected.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(URS)
-	@Produces(XML)
-	@Description("What is the list of usage records that have been collected?")
-	URList usageRecords();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(URS)
-	@Description("What is the list of usage records that have been collected?")
-	Response optionsUsageRecords();
-
-	/**
-	 * What are the current list of workflow URIs that may be started? Empty
-	 * means allow any, including user-supplied workflows.
-	 * 
-	 * @return List of URIs, encoded as strings.
-	 */
-	@GET
-	@Path(PERM_WF)
-	@Produces({ XML, JSON })
-	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
-	StringList getPermittedWorkflowURIs();
-
-	/** Do we turn on the generate provenance option by default? */
-	@GET
-	@Path(GEN_PROV)
-	@Produces(PLAIN)
-	@Description("Do we turn on the generate provenance option by default? (boolean)")
-	String getGenerateProvenance();
-
-	/** Do we turn on the generate provenance option by default? */
-	@PUT
-	@Path(GEN_PROV)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Do we turn on the generate provenance option by default? (boolean)")
-	String setGenerateProvenance(String newValue);
-
-	/** Do we turn on the generate provenance option by default? */
-	@OPTIONS
-	@Path(GEN_PROV)
-	@Description("Do we turn on the generate provenance option by default? (boolean)")
-	Response optionsGenerateProvenance();
-
-	/**
-	 * What are the current list of workflow URIs that may be started? Empty
-	 * means allow any, including user-supplied workflows.
-	 * 
-	 * @param permitted
-	 *            List of URIs, encoded as strings.
-	 * @return List of URIs, encoded as strings.
-	 */
-	@PUT
-	@Path(PERM_WF)
-	@Consumes(XML)
-	@Produces({ XML, JSON })
-	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
-	StringList setPermittedWorkflowURIs(@Nonnull StringList permitted);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(PERM_WF)
-	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
-	Response optionsPermittedWorkflowURIs();
-
-	@GET
-	@Path(USERS)
-	@Produces({ XML, JSON })
-	@Description("What users are known to the server?")
-	UserList users(@Context UriInfo ui);
-
-	@GET
-	@Path(USER)
-	@Produces({ XML, JSON })
-	@Description("What do we know about a particular user?")
-	UserDesc user(@PathParam("id") String username);
-
-	@POST
-	@Path(USERS)
-	@Consumes(XML)
-	@Description("Create a user.")
-	Response useradd(UserDesc userdesc, @Nonnull @Context UriInfo ui);
-
-	@PUT
-	@Path(USER)
-	@Produces({ XML, JSON })
-	@Consumes(XML)
-	@Description("Update a user.")
-	UserDesc userset(@PathParam("id") String username, UserDesc userdesc);
-
-	@DELETE
-	@Path(USER)
-	@Produces({ XML, JSON })
-	@Description("What do we know about a particular user?")
-	Response userdel(@PathParam("id") String username);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(USERS)
-	@Description("What users are known to the server?")
-	Response optionsUsers();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(USER)
-	@Description("What do we know about a particular user?")
-	Response optionsUser(@PathParam("id") String username);
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	/**
-	 * The description of what properties are supported by the administration
-	 * interface.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "description")
-	@XmlType(name = "Description")
-	public static class AdminDescription extends VersionedElement {
-		public Uri allowNew;
-		public Uri logWorkflows;
-		public Uri logFaults;
-		public Uri usageRecordDumpFile;
-		public Uri invokationCount;
-		public Uri runCount;
-		public Uri registryHost;
-		public Uri registryPort;
-		public Uri runLimit;
-		public Uri defaultLifetime;
-		public Uri currentRuns;
-		public Uri javaBinary;
-		public Uri extraArguments;
-		public Uri serverWorkerJar;
-		public Uri serverForkerJar;
-		public Uri executeWorkflowScript;
-		public Uri registrationWaitSeconds;
-		public Uri registrationPollMillis;
-		public Uri runasPasswordFile;
-		public Uri startupTime;
-		public Uri lastExitCode;
-		public Uri factoryProcessMapping;
-		public Uri usageRecords;
-		public Uri users;
-		public Uri operatingLimit;
-		public Uri operatingCount;
-		public Uri permittedWorkflowURIs;
-		public Uri generateProvenance;
-
-		public AdminDescription() {
-		}
-
-		public AdminDescription(UriInfo ui) {
-			allowNew = new Uri(ui, ALLOW_NEW);
-			logWorkflows = new Uri(ui, LOG_WFS);
-			logFaults = new Uri(ui, LOG_EXN);
-			usageRecordDumpFile = new Uri(ui, UR_FILE);
-			invokationCount = new Uri(ui, INVOKES);
-			runCount = new Uri(ui, TOTAL_RUNS);
-			registryHost = new Uri(ui, REG_HOST);
-			registryPort = new Uri(ui, REG_PORT);
-			runLimit = new Uri(ui, RUN_LIMIT);
-			defaultLifetime = new Uri(ui, LIFE);
-			currentRuns = new Uri(ui, RUNS);
-			javaBinary = new Uri(ui, JAVA);
-			extraArguments = new Uri(ui, ARGS);
-			serverWorkerJar = new Uri(ui, JAR_WORKER);
-			serverForkerJar = new Uri(ui, JAR_FORKER);
-			executeWorkflowScript = new Uri(ui, EXEC_WF);
-			registrationWaitSeconds = new Uri(ui, REG_WAIT);
-			registrationPollMillis = new Uri(ui, REG_POLL);
-			runasPasswordFile = new Uri(ui, PASSFILE);
-			startupTime = new Uri(ui, STARTUP);
-			lastExitCode = new Uri(ui, EXITCODE);
-			factoryProcessMapping = new Uri(ui, FACTORIES);
-			usageRecords = new Uri(ui, URS);
-			users = new Uri(ui, USERS);
-			operatingLimit = new Uri(ui, OP_LIMIT);
-			operatingCount = new Uri(ui, OPERATING);
-			permittedWorkflowURIs = new Uri(ui, PERM_WF);
-			generateProvenance = new Uri(ui, GEN_PROV);
-		}
-	}
-
-	/**
-	 * A list of strings, as XML.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "stringList")
-	@XmlType(name = "StringList")
-	public static class StringList {
-		@XmlElement
-		public List<String> string = new ArrayList<>();
-	}
-
-	/**
-	 * A list of users, as XML.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "userList")
-	@XmlType(name = "UserList")
-	public static class UserList {
-		@XmlElement
-		public List<URI> user = new ArrayList<>();
-	}
-
-	@XmlRootElement(name = "userDesc")
-	@XmlType(name = "UserDesc")
-	public static class UserDesc {
-		@XmlElement
-		public String username;
-		@XmlElement
-		public String password;
-		@XmlElement
-		public String localUserId;
-		@XmlElement
-		public Boolean enabled;
-		@XmlElement
-		public Boolean admin;
-	}
-
-	/**
-	 * A list of usage records, as XML.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "usageRecordList")
-	@XmlType(name = "UsageRecords")
-	public static class URList {
-		@XmlElement
-		public List<JobUsageRecord> usageRecord;
-	}
-}
-
-interface Paths {
-	static final String ROOT = "/";
-	static final String ALLOW_NEW = "allowNew";
-	static final String LOG_WFS = "logWorkflows";
-	static final String LOG_EXN = "logFaults";
-	static final String UR_FILE = "usageRecordDumpFile";
-	static final String INVOKES = "invokationCount";
-	static final String TOTAL_RUNS = "runCount";
-	static final String OPERATING = "operatingCount";
-	static final String REG_HOST = "registryHost";
-	static final String REG_PORT = "registryPort";
-	static final String REG_JAR = "registryJar";
-	static final String RUN_LIMIT = "runLimit";
-	static final String OP_LIMIT = "operatingLimit";
-	static final String LIFE = "defaultLifetime";
-	static final String RUNS = "currentRuns";
-	static final String JAVA = "javaBinary";
-	static final String ARGS = "extraArguments";
-	static final String JAR_WORKER = "serverWorkerJar";
-	static final String JAR_FORKER = "serverForkerJar";
-	static final String EXEC_WF = "executeWorkflowScript";
-	static final String REG_WAIT = "registrationWaitSeconds";
-	static final String REG_POLL = "registrationPollMillis";
-	static final String PASSFILE = "runasPasswordFile";
-	static final String STARTUP = "startupTime";
-	static final String EXITCODE = "lastExitCode";
-	static final String FACTORIES = "factoryProcessMapping";
-	static final String URS = "usageRecords";
-	static final String PERM_WF = "permittedWorkflowURIs";
-	static final String GEN_PROV = "generateProvenance";
-	static final String USERS = "users";
-	static final String USER = USERS + "/{id}";
-}
-
-interface Types {
-	static final String PLAIN = "text/plain";
-	static final String XML = "application/xml";
-	static final String JSON = "application/json";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java
deleted file mode 100644
index 0233cd5..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- */
-package org.taverna.server.master.admin;
-/*
- * 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.
- */
-
-import static java.util.Arrays.asList;
-import static java.util.UUID.randomUUID;
-import static javax.ws.rs.core.Response.created;
-import static javax.ws.rs.core.Response.noContent;
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.commons.io.IOUtils;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.exceptions.GeneralFailureException;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.identity.User;
-import org.taverna.server.master.identity.UserStoreAPI;
-import org.taverna.server.master.usage.UsageRecordRecorder;
-import org.taverna.server.master.utils.InvocationCounter;
-import org.taverna.server.master.worker.RunDBSupport;
-import org.taverna.server.master.worker.WorkerModel;
-
-/**
- * The administration interface to Taverna Server.
- * 
- * @author Donal Fellows
- */
-public class AdminBean implements Admin {
-	@Required
-	public void setState(ManagementModel state) {
-		this.state = state;
-	}
-
-	@Required
-	public void setCounter(InvocationCounter counter) {
-		this.counter = counter;
-	}
-
-	@Required
-	public void setRunDB(RunDBSupport runDB) {
-		this.runDB = runDB;
-	}
-
-	@Required
-	public void setFactory(ConfigurableRunFactory factory) {
-		this.factory = factory;
-	}
-
-	@Required
-	public void setUsageRecords(UsageRecordRecorder usageRecords) {
-		this.usageRecords = usageRecords;
-	}
-
-	@Required
-	public void setUserStore(UserStoreAPI userStore) {
-		this.userStore = userStore;
-	}
-
-	@Required
-	public void setLocalWorkerModel(WorkerModel worker) {
-		localWorker = worker;
-	}
-
-	public void setAdminHtmlFile(String filename) {
-		this.adminHtmlFile = filename;
-	}
-
-	public void setResourceRoot(String root) {
-		this.resourceRoot = root;
-	}
-
-	protected byte[] getResource(String name) throws IOException {
-		if (AdminBean.class.getResource(name) == null)
-			throw new FileNotFoundException(name);
-		return IOUtils.toByteArray(AdminBean.class.getResourceAsStream(name));
-	}
-
-	private ManagementModel state;
-	private InvocationCounter counter;
-	private RunDBSupport runDB;
-	private ConfigurableRunFactory factory;
-	private UsageRecordRecorder usageRecords;
-	private UserStoreAPI userStore;
-	private WorkerModel localWorker;
-	private String adminHtmlFile = "/admin.html";
-	private String resourceRoot = "/static/";
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response getUserInterface() throws IOException {
-		return Response.ok(getResource(adminHtmlFile), "text/html").build();
-	}
-
-	@Override
-	@RolesAllowed(ADMIN)
-	public Response getStaticResource(String file) throws IOException {
-		if (file.matches("^[-_.a-zA-Z0-9]+$")) {
-			String type = "application/octet-stream";
-			if (file.endsWith(".html"))
-				type = "text/html";
-			else if (file.endsWith(".js"))
-				type = "text/javascript";
-			else if (file.endsWith(".jpg"))
-				type = "image/jpeg";
-			else if (file.endsWith(".gif"))
-				type = "image/gif";
-			else if (file.endsWith(".png"))
-				type = "image/png";
-			else if (file.endsWith(".svg"))
-				type = "image/svg+xml";
-			else if (file.endsWith(".css"))
-				type = "text/css";
-			try {
-				return Response.ok(getResource(resourceRoot + file), type)
-						.build();
-			} catch (IOException e) {
-				// ignore; we just treat as 404
-			}
-		}
-		return Response.status(NOT_FOUND).entity("no such resource").build();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public AdminDescription getDescription(UriInfo ui) {
-		return new AdminDescription(ui);
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRoot() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean getAllowNew() {
-		return state.getAllowNewWorkflowRuns();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean setAllowNew(boolean newValue) {
-		state.setAllowNewWorkflowRuns(newValue);
-		return state.getAllowNewWorkflowRuns();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsAllowNew() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean getLogWorkflows() {
-		return state.getLogIncomingWorkflows();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean setLogWorkflows(boolean newValue) {
-		state.setLogIncomingWorkflows(newValue);
-		return state.getLogIncomingWorkflows();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsLogWorkflows() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean getLogFaults() {
-		return state.getLogOutgoingExceptions();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean setLogFaults(boolean newValue) {
-		state.setLogOutgoingExceptions(newValue);
-		return state.getLogOutgoingExceptions();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsLogFaults() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getURFile() {
-		return state.getUsageRecordLogFile();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setURFile(String newValue) {
-		state.setUsageRecordLogFile(newValue);
-		return state.getUsageRecordLogFile();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsURFile() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int invokeCount() {
-		return counter.getCount();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsInvokationCount() {
-		return opt();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int runCount() {
-		return runDB.countRuns();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRunCount() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getRegistryHost() {
-		return factory.getRegistryHost();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setRegistryHost(String newValue) {
-		factory.setRegistryHost(newValue);
-		return factory.getRegistryHost();
-	}
-
-	@Override
-	public Response optionsRegistryHost() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getRegistryPort() {
-		return factory.getRegistryPort();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setRegistryPort(int newValue) {
-		factory.setRegistryPort(newValue);
-		return factory.getRegistryPort();
-	}
-
-	@Override
-	public Response optionsRegistryPort() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getRegistryJar() {
-		return factory.getRmiRegistryJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setRegistryJar(String registryJar) {
-		factory.setRmiRegistryJar(registryJar);
-		return factory.getRmiRegistryJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRegistryJar() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getRunLimit() {
-		return factory.getMaxRuns();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setRunLimit(int newValue) {
-		factory.setMaxRuns(newValue);
-		return factory.getMaxRuns();
-	}
-
-	@Override
-	public Response optionsRunLimit() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getDefaultLifetime() {
-		return factory.getDefaultLifetime();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setDefaultLifetime(int newValue) {
-		factory.setDefaultLifetime(newValue);
-		return factory.getDefaultLifetime();
-	}
-
-	@Override
-	public Response optionsDefaultLifetime() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList currentRuns() {
-		StringList result = new StringList();
-		result.string = runDB.listRunNames();
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsCurrentRuns() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getJavaBinary() {
-		return factory.getJavaBinary();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setJavaBinary(String newValue) {
-		factory.setJavaBinary(newValue);
-		return factory.getJavaBinary();
-	}
-
-	@Override
-	public Response optionsJavaBinary() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList getExtraArguments() {
-		String[] xargs = factory.getExtraArguments();
-		StringList result = new StringList();
-		result.string = asList(xargs == null ? new String[0] : xargs);
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList setExtraArguments(StringList newValue) {
-		if (newValue == null || newValue.string == null)
-			factory.setExtraArguments(new String[0]);
-		else
-			factory.setExtraArguments(newValue.string
-					.toArray(new String[newValue.string.size()]));
-		StringList result = new StringList();
-		result.string = asList(factory.getExtraArguments());
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsExtraArguments() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getServerWorkerJar() {
-		return factory.getServerWorkerJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setServerWorkerJar(String newValue) {
-		factory.setServerWorkerJar(newValue);
-		return factory.getServerWorkerJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsServerWorkerJar() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getExecuteWorkflowScript() {
-		return factory.getExecuteWorkflowScript();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setExecuteWorkflowScript(String newValue) {
-		factory.setExecuteWorkflowScript(newValue);
-		return factory.getExecuteWorkflowScript();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsExecuteWorkflowScript() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getRegistrationWaitSeconds() {
-		return factory.getWaitSeconds();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setRegistrationWaitSeconds(int newValue) {
-		factory.setWaitSeconds(newValue);
-		return factory.getWaitSeconds();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRegistrationWaitSeconds() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getRegistrationPollMillis() {
-		return factory.getSleepTime();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setRegistrationPollMillis(int newValue) {
-		factory.setSleepTime(newValue);
-		return factory.getSleepTime();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRegistrationPollMillis() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getRunasPasswordFile() {
-		return factory.getPasswordFile();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setRunasPasswordFile(String newValue) {
-		factory.setPasswordFile(newValue);
-		return factory.getPasswordFile();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRunasPasswordFile() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getServerForkerJar() {
-		return factory.getServerForkerJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setServerForkerJar(String newValue) {
-		factory.setServerForkerJar(newValue);
-		return factory.getServerForkerJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsServerForkerJar() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int startupTime() {
-		return factory.getLastStartupCheckCount();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsStartupTime() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Integer lastExitCode() {
-		return factory.getLastExitCode();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsLastExitCode() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList factoryProcessMapping() {
-		StringList result = new StringList();
-		result.string = asList(factory.getFactoryProcessMapping());
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsFactoryProcessMapping() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public URList usageRecords() {
-		URList result = new URList();
-		result.usageRecord = usageRecords.getUsageRecords();
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsUsageRecords() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public UserList users(UriInfo ui) {
-		UserList ul = new UserList();
-		UriBuilder ub = secure(ui).path("{id}");
-		for (String user : userStore.getUserNames())
-			ul.user.add(ub.build(user));
-		return ul;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsUsers() {
-		return opt("POST");
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public UserDesc user(String username) {
-		UserDesc desc = new UserDesc();
-		User u = userStore.getUser(username);
-		desc.username = u.getUsername();
-		desc.localUserId = u.getLocalUsername();
-		desc.admin = u.isAdmin();
-		desc.enabled = u.isEnabled();
-		return desc;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsUser(String username) {
-		return opt("PUT", "DELETE");
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response useradd(UserDesc userdesc, UriInfo ui) {
-		if (userdesc.username == null)
-			throw new IllegalArgumentException("no user name supplied");
-		if (userdesc.password == null)
-			userdesc.password = randomUUID().toString();
-		userStore.addUser(userdesc.username, userdesc.password, false);
-		if (userdesc.localUserId != null)
-			userStore.setUserLocalUser(userdesc.username, userdesc.localUserId);
-		if (userdesc.admin != null && userdesc.admin)
-			userStore.setUserAdmin(userdesc.username, true);
-		if (userdesc.enabled != null && userdesc.enabled)
-			userStore.setUserEnabled(userdesc.username, true);
-		return created(secure(ui).path("{id}").build(userdesc.username))
-				.build();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public UserDesc userset(String username, UserDesc userdesc) {
-		if (userdesc.password != null)
-			userStore.setUserPassword(username, userdesc.password);
-		if (userdesc.localUserId != null)
-			userStore.setUserLocalUser(username, userdesc.localUserId);
-		if (userdesc.admin != null)
-			userStore.setUserAdmin(username, userdesc.admin);
-		if (userdesc.enabled != null)
-			userStore.setUserEnabled(username, userdesc.enabled);
-		userdesc = null; // Stop reuse!
-
-		UserDesc desc = new UserDesc();
-		User u = userStore.getUser(username);
-		desc.username = u.getUsername();
-		desc.localUserId = u.getLocalUsername();
-		desc.admin = u.isAdmin();
-		desc.enabled = u.isEnabled();
-		return desc;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response userdel(String username) {
-		userStore.deleteUser(username);
-		return noContent().build();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int operatingCount() {
-		try {
-			return factory.getOperatingCount();
-		} catch (Exception e) {
-			throw new GeneralFailureException(e);
-		}
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsOperatingCount() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getOperatingLimit() {
-		return factory.getOperatingLimit();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setOperatingLimit(int operatingLimit) {
-		factory.setOperatingLimit(operatingLimit);
-		return factory.getOperatingLimit();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsOperatingLimit() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList getPermittedWorkflowURIs() {
-		StringList sl = new StringList();
-		List<URI> uris = localWorker.getPermittedWorkflowURIs();
-		if (uris != null)
-			for (URI uri : uris)
-				sl.string.add(uri.toString());
-		return sl;
-	}
-
-	private static final URI myExp = URI.create("http://www.myexperment.org/");
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList setPermittedWorkflowURIs(StringList permitted) {
-		List<URI> uris = new ArrayList<>();
-		for (String uri : permitted.string)
-			try {
-				uris.add(myExp.resolve(uri));
-			} catch (Exception e) {
-				// Ignore
-			}
-		localWorker.setPermittedWorkflowURIs(uris);
-		return getPermittedWorkflowURIs();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsPermittedWorkflowURIs() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getGenerateProvenance() {
-		return Boolean.toString(localWorker.getGenerateProvenance());
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setGenerateProvenance(String newValue) {
-		boolean b = Boolean.parseBoolean(newValue);
-		localWorker.setGenerateProvenance(b);
-		return Boolean.toString(localWorker.getGenerateProvenance());
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsGenerateProvenance() {
-		return opt("PUT");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java
deleted file mode 100644
index 0a4174e..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- */
-/**
- * This package contains the RESTful administration interface to Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = ADMIN, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN),
-		@XmlNs(prefix = "ur", namespaceURI = UR),
-		@XmlNs(prefix = "ds", namespaceURI = XSIG) })
-package org.taverna.server.master.admin;
-/*
- * 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.
- */
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.UR;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.Namespaces.XSIG;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java
deleted file mode 100644
index 2ad6063..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- */
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonList;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
-import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE;
-
-import java.util.List;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Variant;
-
-/**
- * The content types supported at various points in the REST interface.
- * 
- * @author Donal Fellows
- */
-public interface ContentTypes {
-	/** "application/zip" */
-	public static final MediaType APPLICATION_ZIP_TYPE = new MediaType(
-			"application", "zip");
-
-	/** "application/vnd.taverna.baclava+xml" */
-	public static final MediaType BACLAVA_MEDIA_TYPE = new MediaType(
-			"application", "vnd.taverna.baclava+xml");
-
-	/**
-	 * The media types that we are willing to serve up directories as. Note that
-	 * we <i>only</i> serve directories up as these.
-	 */
-	public static final List<Variant> DIRECTORY_VARIANTS = asList(new Variant(
-			APPLICATION_XML_TYPE, (String) null, "UTF-8"), new Variant(
-			APPLICATION_JSON_TYPE, (String) null, "UTF-8"), new Variant(
-			APPLICATION_ZIP_TYPE, (String) null, null));
-
-	/**
-	 * The baseline set of media types that we are willing to serve up files as.
-	 * Note that we <i>also</i> serve files up as their auto-detected media
-	 * type. In all cases, this means we just shovel the bytes (or characters,
-	 * in the case of <tt>text/*</tt> subtypes) back at the client.
-	 */
-	public static final List<Variant> INITIAL_FILE_VARIANTS = singletonList(new Variant(
-			APPLICATION_OCTET_STREAM_TYPE, (String) null, null));
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java
deleted file mode 100644
index 7cb1b7e..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import org.taverna.server.master.rest.TavernaServerDirectoryREST;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.FilenameUtils;
-
-/**
- * Description of properties supported by {@link DirectoryREST}.
- * 
- * @author Donal Fellows
- */
-public interface DirectoryBean extends SupportAware {
-	void setFileUtils(FilenameUtils fileUtils);
-
-	TavernaServerDirectoryREST connect(TavernaRun run);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java
deleted file mode 100644
index c977974..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import org.taverna.server.master.InteractionFeed;
-import org.taverna.server.master.interaction.InteractionFeedSupport;
-
-/**
- * Description of properties supported by {@link InteractionFeed}.
- * 
- * @author Donal Fellows
- */
-public interface FeedBean {
-	void setInteractionFeedSupport(InteractionFeedSupport feed);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java
deleted file mode 100644
index 17003e5..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import javax.ws.rs.core.UriInfo;
-
-import org.taverna.server.master.ContentsDescriptorBuilder;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerInputREST;
-import org.taverna.server.master.utils.FilenameUtils;
-
-/**
- * Description of properties supported by {@link org.taverna.server.master.InputREST}.
- * 
- * @author Donal Fellows
- */
-public interface InputBean extends SupportAware {
-	TavernaServerInputREST connect(TavernaRun run, UriInfo ui);
-
-	void setCdBuilder(ContentsDescriptorBuilder cd);
-
-	void setFileUtils(FilenameUtils fn);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java
deleted file mode 100644
index 52a52f2..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-
-/**
- * Description of properties supported by {@link ListenerPropertyREST}.
- * 
- * @author Donal Fellows
- */
-public interface ListenerPropertyBean extends SupportAware {
-	TavernaServerListenersREST.Property connect(Listener listen,
-			TavernaRun run, String propertyName);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java
deleted file mode 100644
index 63035f7..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-
-/**
- * Description of properties supported by {@link ListenersREST}.
- * 
- * @author Donal Fellows
- */
-public interface ListenersBean extends SupportAware {
-	TavernaServerListenersREST connect(TavernaRun run);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java
deleted file mode 100644
index dc02279..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- */
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-/**
- * The model of the webapp's state Java Bean.
- * 
- * @author Donal Fellows
- */
-public interface ManagementModel {
-	/**
-	 * @return whether we allow the creation of new workflow runs.
-	 */
-	boolean getAllowNewWorkflowRuns();
-
-	/**
-	 * @return whether we should log all workflows sent to us.
-	 */
-	boolean getLogIncomingWorkflows();
-
-	/**
-	 * @return whether outgoing exceptions should be logged before being
-	 *         converted to responses.
-	 */
-	boolean getLogOutgoingExceptions();
-
-	/**
-	 * @return the file that all usage records should be appended to, or
-	 *         <tt>null</tt> if they should be just dropped.
-	 */
-	String getUsageRecordLogFile();
-
-	/**
-	 * @param logIncomingWorkflows
-	 *            whether we should log all workflows sent to us.
-	 */
-	void setLogIncomingWorkflows(boolean logIncomingWorkflows);
-
-	/**
-	 * @param allowNewWorkflowRuns
-	 *            whether we allow the creation of new workflow runs.
-	 */
-	void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns);
-
-	/**
-	 * @param logOutgoingExceptions
-	 *            whether outgoing exceptions should be logged before being
-	 *            converted to responses.
-	 */
-	void setLogOutgoingExceptions(boolean logOutgoingExceptions);
-
-	/**
-	 * @param usageRecordLogFile
-	 *            the file that all usage records should be appended to, or
-	 *            <tt>null</tt> if they should be just dropped.
-	 */
-	void setUsageRecordLogFile(String usageRecordLogFile);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java
deleted file mode 100644
index f7a7134..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
-
-/**
- * Description of properties supported by {@link InputREST}.
- * 
- * @author Donal Fellows
- */
-public interface OneListenerBean {
-	TavernaServerListenerREST connect(Listener listen, TavernaRun run);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java
deleted file mode 100644
index 274d9f0..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import org.taverna.server.master.ContentsDescriptorBuilder;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * Description of properties supported by {@link org.taverna.server.master.RunREST}.
- * 
- * @author Donal Fellows
- */
-public interface RunBean extends SupportAware {
-	void setCdBuilder(ContentsDescriptorBuilder cdBuilder);
-
-	void setRun(TavernaRun run);
-
-	void setRunName(String runName);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java
deleted file mode 100644
index ddbc9b9..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-
-/**
- * Description of properties supported by {@link RunSecurityREST}.
- * 
- * @author Donal Fellows
- */
-public interface SecurityBean extends SupportAware {
-	TavernaServerSecurityREST connect(TavernaSecurityContext context, TavernaRun run);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java
deleted file mode 100644
index 117533f..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.TavernaServerSupport;
-
-/**
- * Indicates that this is a class that wants to be told by Spring about the
- * main support bean.
- * 
- * @author Donal Fellows
- */
-public interface SupportAware {
-	/**
-	 * How to tell the bean about the support bean.
-	 * 
-	 * @param support
-	 *            Reference to the support bean.
-	 */
-	@Required
-	void setSupport(TavernaServerSupport support);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java
deleted file mode 100644
index 8873857..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- */
-package org.taverna.server.master.api;
-/*
- * 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.
- */
-
-import javax.annotation.Nonnull;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.ContentsDescriptorBuilder;
-import org.taverna.server.master.TavernaServerSupport;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.notification.NotificationEngine;
-import org.taverna.server.master.notification.atom.EventDAO;
-import org.taverna.server.master.rest.TavernaServerREST;
-import org.taverna.server.master.soap.TavernaServerSOAP;
-import org.taverna.server.master.utils.FilenameUtils;
-
-/**
- * The methods of the webapp that are accessed by beans other than itself or
- * those which are told directly about it. This exists so that an AOP proxy can
- * be installed around it.
- * 
- * @author Donal Fellows
- */
-public interface TavernaServerBean extends TavernaServerSOAP, TavernaServerREST,
-		UriBuilderFactory {
-	/**
-	 * @param policy
-	 *            The policy being installed by Spring.
-	 */
-	@Required
-	void setPolicy(@Nonnull Policy policy);
-
-	/**
-	 * @param runStore
-	 *            The run store being installed by Spring.
-	 */
-	@Required
-	void setRunStore(@Nonnull RunStore runStore);
-
-	/**
-	 * @param converter
-	 *            The filename converter being installed by Spring.
-	 */
-	@Required
-	void setFileUtils(@Nonnull FilenameUtils converter);
-
-	/**
-	 * @param cdBuilder
-	 *            The contents descriptor builder being installed by Spring.
-	 */
-	@Required
-	void setContentsDescriptorBuilder(
-			@Nonnull ContentsDescriptorBuilder cdBuilder);
-
-	/**
-	 * @param notificationEngine
-	 *            The notification engine being installed by Spring.
-	 */
-	@Required
-	void setNotificationEngine(@Nonnull NotificationEngine notificationEngine);
-
-	/**
-	 * @param support
-	 *            The support bean being installed by Spring.
-	 */
-	@Required
-	void setSupport(@Nonnull TavernaServerSupport support);
-
-	/**
-	 * @param eventSource
-	 *            The event source bean being installed by Spring.
-	 */
-	@Required
-	void setEventSource(@Nonnull EventDAO eventSource);
-
-	/**
-	 * The nastier parts of security initialisation in SOAP calls, which we want
-	 * to go away.
-	 * 
-	 * @param context
-	 *            The context to configure.
-	 * @return True if we did <i>not</i> initialise things.
-	 */
-	boolean initObsoleteSOAPSecurity(@Nonnull TavernaSecurityContext context);
-
-	/**
-	 * The nastier parts of security initialisation in REST calls, which we want
-	 * to go away.
-	 * 
-	 * @param context
-	 *            The context to configure.
-	 * @return True if we did <i>not</i> initialise things.
-	 */
-	boolean initObsoleteRESTSecurity(@Nonnull TavernaSecurityContext context);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/api/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/package-info.java
deleted file mode 100644
index 0966e24..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * API <tt>interface</tt>s for the main service classes.
- * 
- * @author Donal Fellows
- */
-package org.taverna.server.master.api;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Capability.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Capability.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Capability.java
deleted file mode 100644
index 75f9549..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Capability.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import java.net.URI;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * Describes a single capability supported by Taverna Server's workflow
- * execution core.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "Capability")
-public class Capability {
-	@XmlAttribute
-	@XmlSchemaType(name = "anyURI")
-	public URI capability;
-	@XmlAttribute
-	public String version;
-}


[16/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Credential.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Credential.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Credential.java
deleted file mode 100644
index c6627da..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Credential.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.io.Serializable;
-import java.net.URI;
-import java.security.Key;
-import java.security.cert.Certificate;
-
-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.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-import javax.annotation.Nonnull;
-
-/**
- * A description of a private credential. This description is characterised by a
- * file visible to the workflow run that contains a particular key-pair.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "CredentialDescriptor")
-@XmlSeeAlso({ Credential.KeyPair.class, Credential.Password.class })
-@SuppressWarnings("serial")
-public abstract class Credential implements Serializable {
-	/** The location of this descriptor in the REST world. */
-	@XmlAttribute(namespace = XLINK)
-	public String href;
-	/**
-	 * The location of this descriptor in the SOAP world. Must match corrected
-	 * with the {@link #href} field.
-	 */
-	@XmlTransient
-	public String id;
-	/**
-	 * The service URI to use this credential with. If omitted, this represents
-	 * the <i>default</i> credential to use.
-	 */
-	@XmlElement
-	@XmlSchemaType(name = "anyURI")
-	public URI serviceURI;
-	/** The key extracted from the keystore. */
-	public transient Key loadedKey;
-	/** The trust chain of the key extracted from the keystore. */
-	public transient Certificate[] loadedTrustChain;
-
-	@Override
-	public int hashCode() {
-		return id.hashCode();
-	}
-
-	@Override
-	public final boolean equals(Object o) {
-		if (o == null || !(o instanceof Credential))
-			return false;
-		return equals((Credential) o);
-	}
-
-	protected boolean equals(@Nonnull Credential c) {
-		return id.equals(c.id);
-	}
-
-	/**
-	 * A description of a credential that is a public/private key-pair in some
-	 * kind of key store.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "keypair")
-	@XmlType(name = "KeyPairCredential")
-	public static class KeyPair extends Credential {
-		/** The name of the credential within its store, i.e., it's alias. */
-		@XmlElement(required = true)
-		public String credentialName;
-		/**
-		 * The keystore file containing the credential. This is resolved with
-		 * respect to the workflow run working directory.
-		 */
-		@XmlElement
-		public String credentialFile;
-		/**
-		 * The type of keystore file. Defaults to <tt>JKS</tt> if unspecified.
-		 */
-		@XmlElement
-		public String fileType;
-		/**
-		 * The password used to unlock the keystore file. It is assumed that the
-		 * same password is used for unlocking the credential within, or that
-		 * the inner password is empty.
-		 */
-		@XmlElement
-		public String unlockPassword;
-		/**
-		 * The encoded serialized keystore containing the credential.
-		 */
-		@XmlElement
-		public byte[] credentialBytes;
-
-		@Override
-		public String toString() {
-			return "keypair(id=" + id + ")";
-		}
-	}
-
-	/**
-	 * A description of a credential that is a username and password.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "userpass")
-	@XmlType(name = "PasswordCredential")
-	public static class Password extends Credential {
-		@XmlElement(required = true)
-		public String username;
-		@XmlElement(required = true)
-		public String password;
-
-		@Override
-		public String toString() {
-			return "userpass(id=" + id + ")";
-		}
-	}
-
-	/**
-	 * A credential that is just used for deleting credentials by ID. Cannot be
-	 * marshalled as XML.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public static class Dummy extends Credential {
-		public Dummy(String id) {
-			this.id = id;
-		}
-
-		@Override
-		public String toString() {
-			return "dummy(id=" + id + ")";
-		}
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java
deleted file mode 100644
index 424e32a..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.net.URI;
-
-import javax.ws.rs.core.UriBuilder;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-
-/**
- * A reference to something that is in a directory below the working directory
- * of a workflow run, described using JAXB. Note that when creating an XML
- * document containing one of these in a client, it is <i>not</i> necessary to
- * supply any attribute.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "DirectoryEntry")
-@XmlSeeAlso( { DirEntryReference.DirectoryReference.class,
-		DirEntryReference.FileReference.class })
-public class DirEntryReference {
-	/** A link to the entry. Ignored on input. */
-	@XmlAttribute(name = "href", namespace = XLINK)
-	@XmlSchemaType(name = "anyURI")
-	public URI link;
-	/** The last, user-displayable part of the name. Ignored on input. */
-	@XmlAttribute
-	public String name;
-	/** The path of the entry. */
-	@XmlValue
-	public String path;
-
-	/**
-	 * Return the directory entry reference instance subclass suitable for the
-	 * given directory entry.
-	 * 
-	 * @param entry
-	 *            The entry to characterise.
-	 * @return An object that describes the directory entry.
-	 */
-	public static DirEntryReference newInstance(DirectoryEntry entry) {
-		return newInstance(null, entry);
-	}
-
-	/**
-	 * Return the directory entry reference instance subclass suitable for the
-	 * given directory entry.
-	 * 
-	 * @param ub
-	 *            Used for constructing URIs. The {@link #link} field is not
-	 *            filled in if this is <tt>null</tt>.
-	 * @param entry
-	 *            The entry to characterise.
-	 * @return An object that describes the directory entry.
-	 */
-	// Really returns a subclass, so cannot be constructor
-	public static DirEntryReference newInstance(UriBuilder ub,
-			DirectoryEntry entry) {
-		DirEntryReference de = (entry instanceof Directory) ? new DirectoryReference()
-				: new FileReference();
-		de.name = entry.getName();
-		String fullname = entry.getFullName();
-		de.path = fullname.startsWith("/") ? fullname.substring(1) : fullname;
-		if (ub != null)
-			de.link = ub.build(entry.getName());
-		return de;
-	}
-
-	/** A reference to a directory, done with JAXB. */
-	@XmlRootElement(name = "dir")
-	@XmlType(name = "DirectoryReference")
-	public static class DirectoryReference extends DirEntryReference {
-	}
-
-	/** A reference to a file, done with JAXB. */
-	@XmlRootElement(name = "file")
-	@XmlType(name = "FileReference")
-	public static class FileReference extends DirEntryReference {
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java
deleted file mode 100644
index b1eb55c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-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.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * A description of the inputs to a workflow, described using JAXB.
- * 
- * @author Donal Fellows
- */
-@XmlRootElement(name = "inputConfiguration")
-@XmlType(name = "InputConfigurationDescription")
-public class InputDescription extends VersionedElement {
-	/**
-	 * The Baclava file handling the description of the elements. May be
-	 * omitted/<tt>null</tt>.
-	 */
-	@XmlElement(required = false)
-	public String baclavaFile;
-	/**
-	 * The port/value assignment.
-	 */
-	@XmlElement(nillable = false)
-	public List<Port> port = new ArrayList<>();
-
-	/**
-	 * Make a blank input description.
-	 */
-	public InputDescription() {
-	}
-
-	/**
-	 * Make an input description suitable for the given workflow run.
-	 * 
-	 * @param run
-	 */
-	public InputDescription(TavernaRun run) {
-		super(true);
-		baclavaFile = run.getInputBaclavaFile();
-		if (baclavaFile == null)
-			for (Input i : run.getInputs())
-				port.add(new Port(i));
-	}
-
-	/**
-	 * The type of a single port description.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlType(name = "PortConfigurationDescription")
-	public static class Port {
-		/**
-		 * The name of this port.
-		 */
-		@XmlAttribute(name = "portName", required = true)
-		public String name;
-		/**
-		 * The file assigned to this port.
-		 */
-		@XmlAttribute(name = "portFile", required = false)
-		public String file;
-		/**
-		 * The file assigned to this port.
-		 */
-		@XmlAttribute(name = "listDelimiter", required = false)
-		public String delimiter;
-		/**
-		 * The value assigned to this port.
-		 */
-		@XmlValue
-		public String value;
-
-		/**
-		 * Make a blank port description.
-		 */
-		public Port() {
-		}
-
-		/**
-		 * Make a port description suitable for the given input.
-		 * 
-		 * @param input
-		 */
-		public Port(Input input) {
-			name = input.getName();
-			if (input.getFile() != null) {
-				file = input.getFile();
-				value = "";
-			} else {
-				file = null;
-				value = input.getValue();
-			}
-			delimiter = input.getDelimiter();
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java
deleted file mode 100644
index d2035ee..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-/**
- * A convenient place to keep the names of URIs so that they can be got right
- * <i>once</i>.
- * 
- * @author Donal Fellows
- */
-public interface Namespaces {
-	/**
-	 * The XLink specification's namespace name.
-	 */
-	public static final String XLINK = "http://www.w3.org/1999/xlink";
-	/**
-	 * The XML Digital Signature specification's namespace name.
-	 */
-	public static final String XSIG = "http://www.w3.org/2000/09/xmldsig#";
-	/**
-	 * The Usage Record specification's namespace name.
-	 */
-	public static final String UR = "http://schema.ogf.org/urf/2003/09/urf";
-	/**
-	 * The T2flow document format's namespace name.
-	 */
-	public static final String T2FLOW = "http://taverna.sf.net/2008/xml/t2flow";
-	/**
-	 * The namespace for the server.
-	 */
-	public static final String SERVER = "http://ns.taverna.org.uk/2010/xml/server/";
-	public static final String SERVER_REST = SERVER + "rest/";
-	public static final String SERVER_SOAP = SERVER + "soap/";
-	public static final String FEED = SERVER + "feed/";
-	public static final String ADMIN = SERVER + "admin/";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Permission.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Permission.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Permission.java
deleted file mode 100644
index 3e0a307..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Permission.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import javax.xml.bind.annotation.XmlEnum;
-import javax.xml.bind.annotation.XmlEnumValue;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * Description of a permission to access a particular workflow run. Note that
- * users always have full access to their own runs, as does any user with the "
- * <tt>{@value org.taverna.server.master.common.Roles#ADMIN}</tt>" ability.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "Permission")
-@XmlEnum
-public enum Permission {
-	/** Indicates that a user cannot see the workflow run at all. */
-	@XmlEnumValue("none")
-	None,
-	/**
-	 * Indicates that a user can see the workflow run and its contents, but
-	 * can't modify anything.
-	 */
-	@XmlEnumValue("read")
-	Read,
-	/**
-	 * Indicates that a user can update most aspects of a workflow, but cannot
-	 * work with either its security features or its lifetime.
-	 */
-	@XmlEnumValue("update")
-	Update,
-	/**
-	 * Indicates that a user can update almost all aspects of a workflow, with
-	 * only its security features being shrouded.
-	 */
-	@XmlEnumValue("destroy")
-	Destroy
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java
deleted file mode 100644
index d9b0a9e..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-/**
- * Description of the profiles that can apply to a workflow.
- * 
- * @author Donal K. Fellows
- */
-@XmlRootElement(name = "profiles")
-@XmlType(name = "ProfileList")
-public class ProfileList {
-	public List<ProfileList.Info> profile = new ArrayList<ProfileList.Info>();
-
-	/**
-	 * Description of a single workflow profile.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "profile")
-	@XmlType(name = "Profile")
-	public static class Info {
-		@XmlValue
-		public String name;
-		/**
-		 * Whether this is the main profile.
-		 */
-		@XmlAttribute(name = "isMain")
-		public Boolean main;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Roles.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Roles.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Roles.java
deleted file mode 100644
index bdcf876..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Roles.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-/**
- * The roles defined in this webapp.
- * 
- * @author Donal Fellows
- */
-public interface Roles {
-	/** The role of a normal user. */
-	static final String USER = "ROLE_tavernauser";
-	/**
-	 * The role of an administrator. Administrators <i>should</i> have the
-	 * normal user role as well.
-	 */
-	static final String ADMIN = "ROLE_tavernasuperuser";
-	/**
-	 * The role of a workflow accessing itself. Do not give users this role.
-	 */
-	static final String SELF = "ROLE_tavernaworkflow";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java
deleted file mode 100644
index cc80f60..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.VersionedElement.VERSION;
-
-import java.net.URI;
-
-import javax.ws.rs.core.UriBuilder;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-/**
- * A reference to a single workflow run, described using JAXB.
- * 
- * @author Donal Fellows
- * @see org.taverna.server.master.interfaces.TavernaRun TavernaRun
- */
-@XmlRootElement
-@XmlType(name = "TavernaRun")
-@XmlSeeAlso( { Workflow.class, DirEntryReference.class })
-public class RunReference {
-	/**
-	 * Where to get information about the run. For REST.
-	 */
-	@XmlAttribute(name = "href", namespace = XLINK)
-	@XmlSchemaType(name = "anyURI")
-	public URI link;
-	/** What version of server produced this element? */
-	@XmlAttribute(namespace = SERVER)
-	public String serverVersion;
-	/**
-	 * The name of the run. For SOAP.
-	 */
-	@XmlValue
-	public String name;
-
-	/**
-	 * Make a blank run reference.
-	 */
-	public RunReference() {
-	}
-
-	/**
-	 * Make a reference to the given workflow run.
-	 * 
-	 * @param name
-	 *            The name of the run.
-	 * @param ub
-	 *            A factory for URIs, or <tt>null</tt> if none is to be made.
-	 */
-	public RunReference(String name, UriBuilder ub) {
-		this.serverVersion = VERSION;
-		this.name = name;
-		if (ub != null)
-			this.link = ub.build(name);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Status.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Status.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Status.java
deleted file mode 100644
index 1aad4ef..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Status.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import javax.xml.bind.annotation.XmlEnum;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * States of a workflow run. They are {@link #Initialized Initialized},
- * {@link #Operating Operating}, {@link #Stopped Stopped}, and {@link #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
- */
-@XmlEnum
-@XmlType(name = "Status")
-public enum Status {
-	/**
-	 * The workflow run has been created, but is not yet running. The run will
-	 * need to be manually moved to {@link #Operating Operating} when ready.
-	 */
-	Initialized,
-	/**
-	 * The workflow run is going, reading input, generating output, etc. Will
-	 * eventually either move automatically to {@link #Finished Finished} or can
-	 * be moved manually to {@link #Stopped Stopped} (where supported).
-	 */
-	Operating,
-	/**
-	 * The workflow run is paused, and will need to be moved back to
-	 * {@link #Operating 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/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Trust.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Trust.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Trust.java
deleted file mode 100644
index c61e72a..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Trust.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.io.Serializable;
-import java.security.cert.Certificate;
-import java.util.Collection;
-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.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * A description of a trusted identity or identities. This description is
- * characterised by a file visible to the workflow run that contains one or more
- * certificates.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "TrustDescriptor")
-@XmlRootElement(name = "trustedIdentity")
-@SuppressWarnings("serial")
-public final class Trust implements Serializable {
-	/** The location of this descriptor in the REST world. */
-	@XmlAttribute(namespace = XLINK)
-	public String href;
-	/**
-	 * The location of this descriptor in the SOAP world. Must match corrected
-	 * with the {@link #href} field.
-	 */
-	@XmlTransient
-	public String id;
-	/**
-	 * The file containing the certificate(s). This is resolved with respect to
-	 * the workflow run working directory.
-	 */
-	@XmlElement
-	public String certificateFile;
-	/**
-	 * The type of certificate file. Defaults to <tt>X.509</tt> if unspecified.
-	 */
-	@XmlElement
-	public String fileType;
-	/**
-	 * The encoded serialized keystore containing the certificate(s).
-	 */
-	@XmlElement
-	public byte[] certificateBytes;
-	/**
-	 * The names of the server(s) identified by this trust.
-	 */
-	@XmlElement
-	public List<String> serverName;
-	/**
-	 * The collection of certificates loaded from the specified file. This is
-	 * always <tt>null</tt> before validation.
-	 */
-	public transient Collection<? extends Certificate> loadedCertificates;
-
-	@Override
-	public int hashCode() {
-		return id.hashCode();
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if (o == null || !(o instanceof Trust))
-			return false;
-		return id.equals(((Trust) o).id);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Uri.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Uri.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Uri.java
deleted file mode 100644
index ba0bb3c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Uri.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.util.Map;
-
-import javax.annotation.PreDestroy;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriBuilderException;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.web.PortMapper;
-
-import javax.annotation.Nonnull;
-
-/**
- * A class that makes it simpler to work with an element with a {@link URI} in
- * an <tt>href</tt> attribute. Done with JAXB.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "Location")
-public class Uri {
-	static Log log = getLog("Taverna.Server.UriRewriter");
-	private static final String SECURE_SCHEME = "https";
-	/**
-	 * This type is characterised by an attribute that is the reference to some
-	 * other element.
-	 */
-	@XmlAttribute(name = "href", namespace = XLINK)
-	@XmlSchemaType(name = "anyURI")
-	public URI ref;
-
-	/** Make a reference that points nowhere. */
-	public Uri() {
-	}
-
-	/**
-	 * Make a reference to the given location.
-	 * 
-	 * @param ref
-	 *            Where to point to.
-	 */
-	public Uri(@Nonnull URI ref) {
-		this.ref = secure(ref);
-	}
-
-	/**
-	 * Make a reference from the factory with the given parameters.
-	 * 
-	 * @param ub
-	 *            The configured factory.
-	 * @param strings
-	 *            The parameters to the factory.
-	 */
-	public Uri(@Nonnull UriBuilder ub, String... strings) {
-		ref = secure(ub).build((Object[]) strings);
-	}
-
-	/**
-	 * Make a reference from the factory with the given parameters.
-	 * 
-	 * @param ui
-	 *            The factory factory.
-	 * @param path
-	 *            The path to configure the factory with.
-	 * @param strings
-	 *            The parameters to the factory.
-	 */
-	public Uri(@Nonnull UriInfo ui, @Nonnull String path, String... strings) {
-		this(ui, true, path, strings);
-	}
-
-	/**
-	 * Make a reference from the factory with the given parameters.
-	 * 
-	 * @param ui
-	 *            The factory factory.
-	 * @param secure
-	 *            Whether the URI should be required to use HTTPS.
-	 * @param path
-	 *            The path to configure the factory with.
-	 * @param strings
-	 *            The parameters to the factory.
-	 */
-	public Uri(@Nonnull UriInfo ui, boolean secure, @Nonnull String path,
-			String... strings) {
-		UriBuilder ub = ui.getAbsolutePathBuilder();
-		if (secure) {
-			ub = secure(ub);
-		}
-		ref = ub.path(path).build((Object[]) strings);
-	}
-
-	public static UriBuilder secure(UriBuilder ub) {
-		return Rewriter.getInstance().getSecuredUriBuilder(ub);
-	}
-
-	public static UriBuilder secure(UriInfo ui) {
-		return secure(ui.getAbsolutePathBuilder());
-	}
-
-	public static URI secure(URI uri) {
-		URI newURI = secure(fromUri(uri)).build();
-		if (log.isDebugEnabled())
-			log.debug("rewrote " + uri + " to " + newURI);
-		return newURI;
-	}
-
-	public static URI secure(URI base, String uri) {
-		URI newURI = secure(fromUri(base.resolve(uri))).build();
-		if (log.isDebugEnabled())
-			log.debug("rewrote " + uri + " to " + newURI);
-		return newURI;
-	}
-
-	/**
-	 * A bean that allows configuration of how to rewrite generated URIs to be
-	 * secure.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public static class Rewriter {
-		private static Rewriter instance;
-		private PortMapper portMapper;
-		private boolean suppress;
-		private String rewriteRE = "://[^/]+/[^/]+";
-		private String rewriteTarget;
-
-		static Rewriter getInstance() {
-			if (instance == null)
-				new Rewriter();
-			return instance;
-		}
-
-		@Autowired
-		public void setPortMapper(PortMapper portMapper) {
-			this.portMapper = portMapper;
-		}
-
-		/**
-		 * Whether to suppress rewriting of URIs to be secure.
-		 * 
-		 * @param suppressSecurity
-		 *            True if no rewriting should be done.
-		 */
-		public void setSuppressSecurity(boolean suppressSecurity) {
-			suppress = suppressSecurity;
-		}
-
-		public void setRewriteRegexp(String rewriteRegexp) {
-			this.rewriteRE = rewriteRegexp;
-		}
-
-		/**
-		 * What to rewrite the host, port and web-app name to be.
-		 * 
-		 * @param rewriteTarget
-		 *            What to rewrite to, or "<tt>NONE</tt>" for no rewrite.
-		 */
-		public void setRewriteTarget(String rewriteTarget) {
-			if (rewriteTarget.isEmpty())
-				this.rewriteTarget = null;
-			else if (rewriteTarget.equals("NONE"))
-				this.rewriteTarget = null;
-			else if (rewriteTarget.startsWith("${"))
-				this.rewriteTarget = null;
-			else
-				this.rewriteTarget = "://" + rewriteTarget;
-		}
-
-		private Integer lookupHttpsPort(URI uri) {
-			if (portMapper != null)
-				return portMapper.lookupHttpsPort(uri.getPort());
-			return null;
-		}
-
-		public Rewriter() {
-			instance = this;
-		}
-
-		@PreDestroy
-		public void done() {
-			instance = null;
-			Uri.log = null;
-		}
-
-		@Nonnull
-		URI rewrite(@Nonnull String url) {
-			if (rewriteTarget != null)
-				url = url.replaceFirst(rewriteRE, rewriteTarget);
-			return URI.create(url);
-		}
-
-		@Nonnull
-		public UriBuilder getSecuredUriBuilder(@Nonnull UriBuilder uribuilder) {
-			if (suppress)
-				return uribuilder.clone();
-			UriBuilder ub = new RewritingUriBuilder(uribuilder);
-			Integer secPort = null;
-			try {
-				secPort = lookupHttpsPort(ub.build());
-			} catch (Exception e) {
-				/*
-				 * Do not log this; we know why it happens and don't actually
-				 * care to do anything about it. All it does is fill up the log
-				 * with pointless scariness!
-				 */
-
-				// log.debug("failed to extract current URI port", e);
-			}
-			if (secPort == null || secPort.intValue() == -1)
-				return ub.scheme(SECURE_SCHEME);
-			return ub.scheme(SECURE_SCHEME).port(secPort);
-		}
-
-		/**
-		 * {@link UriBuilder} that applies a rewrite rule to the URIs produced
-		 * by the wrapped builder.
-		 * 
-		 * @author Donal Fellows
-		 */
-		class RewritingUriBuilder extends UriBuilder {
-			private UriBuilder wrapped;
-
-			RewritingUriBuilder(UriBuilder builder) {
-				wrapped = builder.clone();
-			}
-
-			private URI rewrite(URI uri) {
-				return Rewriter.this.rewrite(uri.toString());
-			}
-
-			@Override
-			public UriBuilder clone() {
-				return new RewritingUriBuilder(wrapped);
-			}
-
-			@Override
-			public URI buildFromMap(Map<String, ?> values)
-					throws IllegalArgumentException, UriBuilderException {
-				return rewrite(wrapped.buildFromMap(values));
-			}
-
-			@Override
-			public URI buildFromEncodedMap(Map<String, ? extends Object> values)
-					throws IllegalArgumentException, UriBuilderException {
-				return rewrite(wrapped.buildFromEncodedMap(values));
-			}
-
-			@Override
-			public URI build(Object... values) throws IllegalArgumentException,
-					UriBuilderException {
-				return rewrite(wrapped.build(values));
-			}
-
-			@Override
-			public URI build(Object[] values, boolean encodeSlashInPath)
-					throws IllegalArgumentException, UriBuilderException {
-				return rewrite(wrapped.build(values, encodeSlashInPath));
-			}
-
-			@Override
-			public URI buildFromEncoded(Object... values)
-					throws IllegalArgumentException, UriBuilderException {
-				return rewrite(wrapped.buildFromEncoded(values));
-			}
-
-			@Override
-			public URI buildFromMap(Map<String, ?> values,
-					boolean encodeSlashInPath) throws IllegalArgumentException,
-					UriBuilderException {
-				return rewrite(wrapped.buildFromEncoded(values,
-						encodeSlashInPath));
-			}
-
-			@Override
-			public UriBuilder uri(URI uri) throws IllegalArgumentException {
-				wrapped.uri(uri);
-				return this;
-			}
-
-			@Override
-			public UriBuilder uri(String uriTemplate)
-					throws IllegalArgumentException {
-				wrapped.uri(uriTemplate);
-				return this;
-			}
-
-			@Override
-			public String toTemplate() {
-				return wrapped.toTemplate();
-			}
-
-			@Override
-			public UriBuilder scheme(String scheme)
-					throws IllegalArgumentException {
-				wrapped.scheme(scheme);
-				return this;
-			}
-
-			@Override
-			public UriBuilder schemeSpecificPart(String ssp)
-					throws IllegalArgumentException {
-				wrapped.schemeSpecificPart(ssp);
-				return this;
-			}
-
-			@Override
-			public UriBuilder userInfo(String ui) {
-				wrapped.userInfo(ui);
-				return this;
-			}
-
-			@Override
-			public UriBuilder host(String host) throws IllegalArgumentException {
-				wrapped.host(host);
-				return this;
-			}
-
-			@Override
-			public UriBuilder port(int port) throws IllegalArgumentException {
-				wrapped.port(port);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replacePath(String path) {
-				wrapped.replacePath(path);
-				return this;
-			}
-
-			@Override
-			public UriBuilder path(String path) throws IllegalArgumentException {
-				wrapped.path(path);
-				return this;
-			}
-
-			@Override
-			public UriBuilder path(
-					@java.lang.SuppressWarnings("rawtypes") Class resource)
-					throws IllegalArgumentException {
-				wrapped.path(resource);
-				return this;
-			}
-
-			@Override
-			public UriBuilder path(
-					@java.lang.SuppressWarnings("rawtypes") Class resource,
-					String method) throws IllegalArgumentException {
-				wrapped.path(resource, method);
-				return this;
-			}
-
-			@Override
-			public UriBuilder path(Method method)
-					throws IllegalArgumentException {
-				wrapped.path(method);
-				return this;
-			}
-
-			@Override
-			public UriBuilder segment(String... segments)
-					throws IllegalArgumentException {
-				wrapped.segment(segments);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replaceMatrix(String matrix)
-					throws IllegalArgumentException {
-				wrapped.replaceMatrix(matrix);
-				return this;
-			}
-
-			@Override
-			public UriBuilder matrixParam(String name, Object... values)
-					throws IllegalArgumentException {
-				wrapped.matrixParam(name, values);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replaceMatrixParam(String name, Object... values)
-					throws IllegalArgumentException {
-				wrapped.replaceMatrixParam(name, values);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replaceQuery(String query)
-					throws IllegalArgumentException {
-				wrapped.replaceQuery(query);
-				return this;
-			}
-
-			@Override
-			public UriBuilder queryParam(String name, Object... values)
-					throws IllegalArgumentException {
-				wrapped.queryParam(name, values);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replaceQueryParam(String name, Object... values)
-					throws IllegalArgumentException {
-				wrapped.replaceQueryParam(name, values);
-				return this;
-			}
-
-			@Override
-			public UriBuilder fragment(String fragment) {
-				wrapped.fragment(fragment);
-				return this;
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java
deleted file mode 100644
index 735a72d..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.commons.logging.Log;
-
-/**
- * The type of an element that declares the version of the server that produced
- * it.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "VersionedElement", namespace = SERVER)
-public abstract class VersionedElement {
-	/** What version of server produced this element? */
-	@XmlAttribute(namespace = SERVER)
-	public String serverVersion;
-	/** What revision of server produced this element? Derived from SCM commit. */
-	@XmlAttribute(namespace = SERVER)
-	public String serverRevision;
-	/** When was the server built? */
-	@XmlAttribute(namespace = SERVER)
-	public String serverBuildTimestamp;
-	public static final String VERSION, REVISION, TIMESTAMP;
-	static {
-		Log log = getLog("Taverna.Server.Webapp");
-		Properties p = new Properties();
-		try {
-			try (InputStream is = VersionedElement.class
-					.getResourceAsStream("/version.properties")) {
-				p.load(is);
-			}
-		} catch (IOException e) {
-			log.warn("failed to read /version.properties", e);
-		}
-		VERSION = p.getProperty("tavernaserver.version", "unknownVersion");
-		REVISION = String.format("%s (tag: %s)",
-				p.getProperty("tavernaserver.branch", "unknownRevision"),
-				p.getProperty("tavernaserver.revision.describe", "unknownTag"));
-		TIMESTAMP = p
-				.getProperty("tavernaserver.timestamp", "unknownTimestamp");
-	}
-
-	public VersionedElement() {
-	}
-
-	protected VersionedElement(boolean ignored) {
-		serverVersion = VERSION;
-		serverRevision = REVISION;
-		serverBuildTimestamp = TIMESTAMP;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java
deleted file mode 100644
index 3a7d5f7..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- */
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import static javax.xml.bind.Marshaller.JAXB_ENCODING;
-import static javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT;
-import static javax.xml.bind.annotation.XmlAccessType.NONE;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.Serializable;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.net.URL;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAnyElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.taverna.server.master.rest.handler.Scufl2DocumentHandler;
-import org.taverna.server.master.rest.handler.T2FlowDocumentHandler;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
-
-import org.apache.taverna.scufl2.api.common.NamedSet;
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-import org.apache.taverna.scufl2.api.io.ReaderException;
-import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
-import org.apache.taverna.scufl2.api.io.WriterException;
-import org.apache.taverna.scufl2.api.profiles.Profile;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-/**
- * Encapsulation of a T2flow or Scufl2 document.
- * 
- * @author Donal K. Fellows
- */
-@XmlRootElement(name = "workflow")
-@XmlType(name = "Workflow")
-@XmlAccessorType(NONE)
-public class Workflow implements Serializable, Externalizable {
-	/** Literal document, if present. */
-	@XmlAnyElement(lax = true)
-	private Element content;
-	/** SCUFL2 bundle, if present. */
-	@XmlTransient
-	private WorkflowBundle bundle;
-	/** Which came first, the bundle or the t2flow document. */
-	@XmlTransient
-	private boolean isBundleFirst;
-
-	private static Marshaller marshaller;
-	private static Unmarshaller unmarshaller;
-	private final static String ENCODING = "UTF-8";
-	private final static WorkflowBundleIO io;
-	static {
-		try {
-			JAXBContext context = JAXBContext.newInstance(Workflow.class);
-			marshaller = context.createMarshaller();
-			unmarshaller = context.createUnmarshaller();
-			marshaller.setProperty(JAXB_ENCODING, ENCODING);
-			marshaller.setProperty(JAXB_FORMATTED_OUTPUT, false);
-		} catch (JAXBException e) {
-			getLog("Taverna.Server.Webapp").fatal(
-					"failed to build JAXB context for working with "
-							+ Workflow.class, e);
-		}
-		io = new WorkflowBundleIO();
-	}
-
-	public enum ContentType {
-		T2FLOW(T2FlowDocumentHandler.T2FLOW), SCUFL2(
-				Scufl2DocumentHandler.SCUFL2);
-		private String type;
-
-		ContentType(String type) {
-			this.type = type;
-		}
-
-		public String getContentType() {
-			return type;
-		}
-	}
-
-	public Workflow() {
-	}
-
-	public Workflow(Element element) {
-		this.content = element;
-		this.isBundleFirst = false;
-	}
-
-	public Workflow(WorkflowBundle bundle) {
-		this.bundle = bundle;
-		this.isBundleFirst = true;
-	}
-
-	public Workflow(URL url) throws ReaderException, IOException {
-		this(io.readBundle(url, null));
-	}
-
-	/**
-	 * What content type would this workflow "prefer" to be?
-	 */
-	public ContentType getPreferredContentType() {
-		if (isBundleFirst)
-			return ContentType.SCUFL2;
-		else
-			return ContentType.T2FLOW;
-	}
-
-	/**
-	 * Retrieves the workflow as a SCUFL2 document, converting it if necessary.
-	 * 
-	 * @return The SCUFL2 document.
-	 * @throws IOException
-	 *             If anything goes wrong.
-	 */
-	public WorkflowBundle getScufl2Workflow() throws IOException {
-		try {
-			if (bundle == null)
-				bundle = io.readBundle(new ByteArrayInputStream(getAsT2Flow()),
-						T2FLOW);
-			return bundle;
-		} catch (IOException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new IOException("problem when converting to SCUFL2", e);
-		}
-	}
-
-	/**
-	 * Get the bytes of the serialized SCUFL2 workflow.
-	 * 
-	 * @return Array of bytes.
-	 * @throws IOException
-	 *             If serialization fails.
-	 * @throws WriterException
-	 *             If conversion fails.
-	 */
-	public byte[] getScufl2Bytes() throws IOException, WriterException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		io.writeBundle(getScufl2Workflow(), baos, SCUFL2);
-		return baos.toByteArray();
-	}
-
-	/**
-	 * Retrieves the workflow as a T2Flow document, converting it if necessary.
-	 * 
-	 * @return The T2Flow document.
-	 * @throws IOException
-	 *             If anything goes wrong.
-	 */
-	public Element getT2flowWorkflow() throws IOException {
-		try {
-			if (content != null)
-				return content;
-			ByteArrayOutputStream baos = new ByteArrayOutputStream();
-			io.writeBundle(bundle, baos, T2FLOW);
-			Document doc;
-			try {
-				DocumentBuilderFactory dbf = DocumentBuilderFactory
-						.newInstance();
-				dbf.setNamespaceAware(true);
-				doc = dbf.newDocumentBuilder().parse(
-						new ByteArrayInputStream(baos.toByteArray()));
-			} catch (SAXException e) {
-				throw new IOException("failed to convert to DOM tree", e);
-			}
-			Element e = doc.getDocumentElement();
-			if (e.getNamespaceURI().equals(T2FLOW_NS)
-					&& e.getNodeName().equals(T2FLOW_ROOTNAME))
-				return content = e;
-			throw new IOException(
-					"unexpected element when converting to T2Flow: {"
-							+ e.getNamespaceURI() + "}" + e.getNodeName());
-		} catch (IOException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new IOException("problem when converting to SCUFL2", e);
-		}
-	}
-
-	/**
-	 * @return The name of the main workflow profile, or <tt>null</tt> if there
-	 *         is none.
-	 */
-	public String getMainProfileName() {
-		try {
-			return getScufl2Workflow().getMainProfile().getName();
-		} catch (IOException e) {
-			return null;
-		}
-	}
-
-	/**
-	 * @return The set of profiles supported over this workflow.
-	 */
-	public NamedSet<Profile> getProfiles() {
-		try {
-			return getScufl2Workflow().getProfiles();
-		} catch (IOException e) {
-			return new NamedSet<Profile>();
-		}
-	}
-
-	/**
-	 * Convert from marshalled form.
-	 * 
-	 * @throws JAXBException
-	 *             If the conversion fails.
-	 */
-	public static Workflow unmarshal(String representation)
-			throws JAXBException {
-		StringReader sr = new StringReader(representation);
-		return (Workflow) unmarshaller.unmarshal(sr);
-	}
-
-	/**
-	 * Convert to marshalled form.
-	 */
-	public String marshal() throws JAXBException {
-		StringWriter sw = new StringWriter();
-		marshaller.marshal(this, sw);
-		return sw.toString();
-	}
-
-	@Override
-	public void readExternal(ObjectInput in) throws IOException,
-			ClassNotFoundException {
-		try {
-			ByteArrayInputStream bytes = readbytes(in);
-			if (bytes != null)
-				try (Reader r = new InputStreamReader(bytes, ENCODING)) {
-					content = ((Workflow) unmarshaller.unmarshal(r)).content;
-				}
-			bytes = readbytes(in);
-			if (bytes != null)
-				bundle = io.readBundle(bytes, SCUFL2);
-			isBundleFirst = in.readBoolean();
-			return;
-		} catch (JAXBException e) {
-			throw new IOException("failed to unmarshal", e);
-		} catch (ClassCastException e) {
-			throw new IOException("bizarre result of unmarshalling", e);
-		} catch (ReaderException e) {
-			throw new IOException("failed to unmarshal", e);
-		}
-	}
-
-	private byte[] getAsT2Flow() throws IOException, JAXBException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		OutputStreamWriter w = new OutputStreamWriter(baos, ENCODING);
-		marshaller.marshal(this, w);
-		w.close();
-		return baos.toByteArray();
-	}
-
-	private byte[] getAsScufl2() throws IOException, WriterException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		io.writeBundle(bundle, baos, SCUFL2);
-		baos.close();
-		return baos.toByteArray();
-	}
-
-	@Override
-	public void writeExternal(ObjectOutput out) throws IOException {
-		try {
-			writebytes(out, (content != null) ? getAsT2Flow() : null);
-		} catch (JAXBException e) {
-			throw new IOException("failed to marshal t2flow", e);
-		}
-		try {
-			writebytes(out, (bundle != null) ? getAsScufl2() : null);
-		} catch (WriterException e) {
-			throw new IOException("failed to marshal scufl2", e);
-		}
-		out.writeBoolean(isBundleFirst);
-	}
-
-	private ByteArrayInputStream readbytes(ObjectInput in) throws IOException {
-		int len = in.readInt();
-		if (len > 0) {
-			byte[] bytes = new byte[len];
-			in.readFully(bytes);
-			return new ByteArrayInputStream(bytes);
-		}
-		return null;
-	}
-
-	private void writebytes(ObjectOutput out, byte[] data) throws IOException {
-		out.writeInt(data == null ? 0 : data.length);
-		if (data != null && data.length > 0)
-			out.write(data);
-	}
-
-	/**
-	 * Make up for the lack of an integrated XPath engine.
-	 * 
-	 * @param name
-	 *            The element names to look up from the root of the contained
-	 *            document.
-	 * @return The looked up element, or <tt>null</tt> if it doesn't exist.
-	 */
-	private Element getEl(String... name) {
-		Element el = content;
-		boolean skip = true;
-		for (String n : name) {
-			if (skip) {
-				skip = false;
-				continue;
-			}
-			if (el == null)
-				return null;
-			NodeList nl = el.getElementsByTagNameNS(T2FLOW_NS, n);
-			if (nl.getLength() == 0)
-				return null;
-			Node node = nl.item(0);
-			if (node instanceof Element)
-				el = (Element) node;
-			else
-				return null;
-		}
-		return el;
-	}
-
-	/**
-	 * @return The content of the embedded
-	 *         <tt>&lt;workflow&gt;&lt;dataflow&gt;&lt;name&gt;</tt> element.
-	 */
-	@XmlTransient
-	public String getName() {
-		return getEl("workflow", "dataflow", "name").getTextContent();
-	}
-
-	/**
-	 * @return The embedded <tt>&lt;workflow&gt;</tt> element.
-	 */
-	@XmlTransient
-	public Element getWorkflowRoot() {
-		return getEl("workflow");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/package-info.java
deleted file mode 100644
index e000cef..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/package-info.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- */
-/**
- * This package contains the common XML elements used throughout Taverna Server's various interfaces.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.common;
-/*
- * 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.
- */
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.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/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java
deleted file mode 100644
index bd50db2..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- */
-package org.taverna.server.master.common.version;
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import static org.taverna.server.master.common.version.Constants.PATCH;
-import static org.taverna.server.master.common.version.Constants.VERSION;
-
-/**
- * Common location for describing the version of the server.
- * 
- * @author Donal Fellows
- */
-public interface Version {
-	public static final String JAVA = VERSION + Constants.releaseChar + PATCH;
-	public static final String HTML = VERSION + Constants.releaseHEnt + PATCH;
-	public static final String XML = VERSION + Constants.releaseXEnt + PATCH;
-}
-
-/**
- * The pieces of a version string.
- * 
- * @author Donal Fellows
- */
-interface Constants {
-	static final String MAJOR = "3";
-	static final String MINOR = "1";
-	static final String PATCH = "0";
-
-	static final char alphaChar = '\u03b1';
-	static final char betaChar = '\u03b2';
-	static final char releaseChar = '.';
-	static final String alphaHEnt = "&alpha;";
-	static final String betaHEnt = "&beta;";
-	static final String releaseHEnt = ".";
-	static final String alphaXEnt = "&#x03b1;";
-	static final String betaXEnt = "&#x03b2;";
-	static final String releaseXEnt = ".";
-
-	static final String VERSION = MAJOR + "." + MINOR;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java
deleted file mode 100644
index 679a5f4..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- */
-package org.taverna.server.master.defaults;
-/*
- * 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.
- */
-
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.localworker.LocalWorkerState;
-
-/**
- * This defines a collection of default values, collecting them from various
- * parts of the server.
- * 
- * @author Donal Fellows
- */
-public interface Default {
-	/** The default value of the <tt>prefix</tt> property. */
-	static final String AUTHORITY_PREFIX = "LOCALUSER_";
-
-	/**
-	 * The name of the resource that is the implementation of the subprocess
-	 * that this class will fork off.
-	 */
-	static final String SERVER_WORKER_IMPLEMENTATION_JAR = "util/server.worker.jar";
-
-	/**
-	 * The name of the resource that is the implementation of the subprocess
-	 * that manages secure forking.
-	 */
-	static final String SECURE_FORK_IMPLEMENTATION_JAR = "util/secure.fork.jar";
-
-	/**
-	 * The name of the resource that is the implementation of the subprocess
-	 * that acts as the RMI registry.
-	 */
-	static final String REGISTRY_JAR = "util/rmi.daemon.jar";
-
-	/** Initial lifetime of runs, in minutes. */
-	static final int RUN_LIFE_MINUTES = 20;
-
-	/**
-	 * Maximum number of runs to exist at once. Note that this includes when
-	 * they are just existing for the purposes of file transfer (
-	 * {@link Status#Initialized}/{@link Status#Finished} states).
-	 */
-	static final int RUN_COUNT_MAX = 5;
-
-	/**
-	 * Prefix to use for RMI names.
-	 */
-	static final String RMI_PREFIX = "ForkRunFactory.";
-
-	/** Default value for {@link LocalWorkerState#passwordFile}. */
-	static final String PASSWORD_FILE = null;
-
-	/**
-	 * The extra arguments to pass to the subprocess.
-	 */
-	static final String[] EXTRA_ARGUMENTS = new String[0];
-
-	/**
-	 * How long to wait for subprocess startup, in seconds.
-	 */
-	static final int SUBPROCESS_START_WAIT = 40;
-
-	/**
-	 * Polling interval to use during startup, in milliseconds.
-	 */
-	static final int SUBPROCESS_START_POLL_SLEEP = 1000;
-
-	/**
-	 * Maximum number of {@link Status#Operating} runs at any time.
-	 */
-	static final int RUN_OPERATING_LIMIT = 10;
-
-	/**
-	 * What fields of a certificate we look at when understanding who it is
-	 * talking about, in the order that we look.
-	 */
-	static final String[] CERTIFICATE_FIELD_NAMES = { "CN", "COMMONNAME",
-			"COMMON NAME", "COMMON_NAME", "OU", "ORGANIZATIONALUNITNAME",
-			"ORGANIZATIONAL UNIT NAME", "O", "ORGANIZATIONNAME",
-			"ORGANIZATION NAME" };
-
-	/** The type of certificates that are processed if we don't say otherwise. */
-	static final String CERTIFICATE_TYPE = "X.509";
-
-	/** Max size of credential file, in kiB. */
-	static final int CREDENTIAL_FILE_SIZE_LIMIT = 20;
-
-	/**
-	 * The notification message format to use if none is configured.
-	 */
-	public static final String NOTIFY_MESSAGE_FORMAT = "Your job with ID={0} has finished with exit code {1,number,integer}.";
-
-	/** The address of the SMS gateway service used. */
-	public static final String SMS_GATEWAY_URL = "https://www.intellisoftware.co.uk/smsgateway/sendmsg.aspx";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java
deleted file mode 100644
index 5585c77..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * This package contains information about the various default values supported by the server.
- * @author Donal Fellows
- */
-package org.taverna.server.master.defaults;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java
deleted file mode 100644
index 64d07f0..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.ws.WebFault;
-
-/**
- * Indicates that the port name was not recognized.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "BadInputPortNameFault")
-@SuppressWarnings("serial")
-public class BadInputPortNameException extends Exception {
-	public BadInputPortNameException(String msg) {
-		super(msg);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java
deleted file mode 100644
index 61bf740..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.ws.WebFault;
-
-/**
- * Indicates a bad property value.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "BadPropertyValueFault")
-public class BadPropertyValueException extends NoListenerException {
-	private static final long serialVersionUID = -8459491388504556875L;
-
-	public BadPropertyValueException(String msg) {
-		super(msg);
-	}
-
-	public BadPropertyValueException(String msg, Throwable e) {
-		super(msg, e);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java
deleted file mode 100644
index 152410f..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.ws.WebFault;
-
-/**
- * Exception that is thrown to indicate that the state change requested for a
- * run is impossible.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoUpdateFault")
-public class BadStateChangeException extends NoUpdateException {
-	private static final long serialVersionUID = -4490826388447601775L;
-
-	public BadStateChangeException() {
-		super("cannot do that state change");
-	}
-
-	public BadStateChangeException(Throwable t) {
-		super("cannot do that state change", t);
-	}
-
-	public BadStateChangeException(String msg, Throwable t) {
-		super(msg, t);
-	}
-
-	public BadStateChangeException(String message) {
-		super(message);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java
deleted file mode 100644
index e0894e4..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import java.rmi.RemoteException;
-
-import javax.xml.ws.WebFault;
-
-/**
- * An exception that happened when the underlying filesystem was accessed.
- * @author Donal Fellows
- */
-@WebFault(name = "FilesystemAccessFault")
-public class FilesystemAccessException extends Exception {
-	private static final long serialVersionUID = 8715937300989820318L;
-
-	public FilesystemAccessException(String msg) {
-		super(msg);
-	}
-
-	public FilesystemAccessException(String string, Throwable cause) {
-		super(string, getRealCause(cause));
-	}
-
-	private static Throwable getRealCause(Throwable t) {
-		if (t instanceof RemoteException) {
-			RemoteException remote = (RemoteException) t;
-			if (remote.detail != null)
-				return remote.detail;
-		}
-		if (t.getCause() != null)
-			return t.getCause();
-		return t;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java
deleted file mode 100644
index de3fab5..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Some sort of exception that occurred which we can't map any other way. This
- * is generally indicative of a problem server-side.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "GeneralFailureFault", targetNamespace = SERVER_SOAP)
-@SuppressWarnings("serial")
-public class GeneralFailureException extends RuntimeException {
-	public GeneralFailureException(Throwable cause) {
-		super(cause.getMessage(), cause);
-	}
-
-	public GeneralFailureException(String message, Throwable cause) {
-		super(message, cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java
deleted file mode 100644
index 7e00093..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-/**
- * An exception that is thrown to indicate that a credential-descriptor or
- * trust-descriptor supplied as part of a credential or trust management
- * operation is invalid.
- * 
- * @author Donal Fellows
- * 
- */
-@SuppressWarnings("serial")
-public class InvalidCredentialException extends Exception {
-	private static final String MSG = "that credential is invalid";
-
-	public InvalidCredentialException() {
-		super(MSG);
-	}
-
-	public InvalidCredentialException(String reason) {
-		super(MSG + ": " + reason);
-	}
-
-	public InvalidCredentialException(String reason, Throwable cause) {
-		this(reason);
-		initCause(cause);
-	}
-
-	public InvalidCredentialException(Throwable cause) {
-		this(cause.getMessage(), cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java
deleted file mode 100644
index d665adb..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-import javax.xml.ws.WebFault;
-
-
-/**
- * Exception that is thrown to indicate that the user is not permitted to
- * create something.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoCreateFault")
-public class NoCreateException extends NoUpdateException {
-	private static final long serialVersionUID = 270413810410167235L;
-
-	public NoCreateException() {
-		super("not permitted to create");
-	}
-
-	public NoCreateException(String string) {
-		super(string);
-	}
-
-	public NoCreateException(String string, Throwable e) {
-		super(string, e);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java
deleted file mode 100644
index b351c1c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- */
-package org.taverna.server.master.exceptions;
-/*
- * 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.
- */
-
-/**
- * Exception that indicates the absence of an expected credential.
- * 
- * @author Donal Fellows
- */
-@SuppressWarnings("serial")
-public class NoCredentialException extends Exception {
-	public NoCredentialException() {
-		super("no such credential");
-	}
-}



[39/42] incubator-taverna-server git commit: package org.apache.taverna.server.*

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/package-info.java
index 0a1a52f..37552c4 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/package-info.java
@@ -11,7 +11,7 @@
 		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
 		@XmlNs(prefix = "feed", namespaceURI = FEED),
 		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.notification.atom;
+package org.apache.taverna.server.master.notification.atom;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -30,12 +30,12 @@ package org.taverna.server.master.notification.atom;
  */
 
 import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Namespaces.ADMIN;
+import static org.apache.taverna.server.master.common.Namespaces.FEED;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.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/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/package-info.java
index 43335cf..4e35a04 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/package-info.java
@@ -4,7 +4,7 @@
  * The notification fabric and implementations of notification dispatchers
  * that support subscription.
  */
-package org.taverna.server.master.notification;
+package org.apache.taverna.server.master.notification;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/package-info.java
index d912ac8..c79384c 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/package-info.java
@@ -4,7 +4,7 @@
  * The core of the implementation of Taverna Server, including the
  * implementations of the SOAP and REST interfaces.
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ContentTypes.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ContentTypes.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ContentTypes.java
index d9aef82..e4b1d45 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ContentTypes.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ContentTypes.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/DirectoryContents.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/DirectoryContents.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/DirectoryContents.java
index 42d4b0e..ce30852 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/DirectoryContents.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/DirectoryContents.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.rest;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Uri.secure;
+import static org.apache.taverna.server.master.common.Uri.secure;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -31,8 +31,8 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
 
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.interfaces.DirectoryEntry;
+import org.apache.taverna.server.master.common.DirEntryReference;
+import org.apache.taverna.server.master.interfaces.DirectoryEntry;
 
 /**
  * The result of a RESTful operation to list the contents of a directory. Done

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/FileSegment.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/FileSegment.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/FileSegment.java
index 6b7aaff..75b56f9 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/FileSegment.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/FileSegment.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -26,8 +26,8 @@ import java.util.regex.Pattern;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.interfaces.File;
 
 /**
  * Representation of a segment of a file to be read by JAX-RS.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
index 69705d9..a039baa 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.rest;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.rest.ContentTypes.ATOM;
+import static org.apache.taverna.server.master.rest.ContentTypes.ATOM;
 
 import java.net.MalformedURLException;
 
@@ -35,9 +35,9 @@ import javax.ws.rs.core.Response;
 import org.apache.abdera.model.Entry;
 import org.apache.abdera.model.Feed;
 import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
 
 /**
  * A very stripped down ATOM feed for the interaction service.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
index f877d7a..cbee33b 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
index 52e6d04..9cbaf13 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
index 1ed8a64..5f6e7d5 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,12 +20,12 @@ package org.taverna.server.master.rest;
 
 import static java.util.Collections.unmodifiableList;
 import static javax.ws.rs.core.MediaType.WILDCARD;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.BYTES;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.URI_LIST;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.ContentTypes.ZIP;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.rest.ContentTypes.BYTES;
+import static org.apache.taverna.server.master.rest.ContentTypes.JSON;
+import static org.apache.taverna.server.master.rest.ContentTypes.URI_LIST;
+import static org.apache.taverna.server.master.rest.ContentTypes.XML;
+import static org.apache.taverna.server.master.rest.ContentTypes.ZIP;
 
 import java.io.InputStream;
 import java.net.URI;
@@ -50,11 +50,11 @@ import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.core.Variant;
 
 import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.interfaces.File;
 
 /**
  * Representation of how a workflow run's working directory tree looks.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerInputREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerInputREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerInputREST.java
index 154a1eb..64f614f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerInputREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerInputREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,13 +18,13 @@ package org.taverna.server.master.rest;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.TEXT;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.TavernaServerInputREST.PathNames.BACLAVA;
-import static org.taverna.server.master.rest.TavernaServerInputREST.PathNames.EXPECTED;
-import static org.taverna.server.master.rest.TavernaServerInputREST.PathNames.ONE_INPUT;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.rest.ContentTypes.JSON;
+import static org.apache.taverna.server.master.rest.ContentTypes.TEXT;
+import static org.apache.taverna.server.master.rest.ContentTypes.XML;
+import static org.apache.taverna.server.master.rest.TavernaServerInputREST.PathNames.BACLAVA;
+import static org.apache.taverna.server.master.rest.TavernaServerInputREST.PathNames.EXPECTED;
+import static org.apache.taverna.server.master.rest.TavernaServerInputREST.PathNames.ONE_INPUT;
 
 import java.net.URI;
 import java.util.ArrayList;
@@ -53,16 +53,16 @@ import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlValue;
 
 import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.exceptions.BadInputPortNameException;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.port_description.InputDescription;
+import org.apache.taverna.server.master.common.Uri;
+import org.apache.taverna.server.master.common.VersionedElement;
+import org.apache.taverna.server.master.exceptions.BadInputPortNameException;
+import org.apache.taverna.server.master.exceptions.BadPropertyValueException;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.Input;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.port_description.InputDescription;
 
 /**
  * This represents how a Taverna Server workflow run's inputs looks to a RESTful

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerListenersREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerListenersREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerListenersREST.java
index e554997..fe7af90 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerListenersREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerListenersREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,11 +18,11 @@ package org.taverna.server.master.rest;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.TEXT;
-import static org.taverna.server.master.rest.ContentTypes.XML;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.rest.ContentTypes.JSON;
+import static org.apache.taverna.server.master.rest.ContentTypes.TEXT;
+import static org.apache.taverna.server.master.rest.ContentTypes.XML;
 
 import java.net.URI;
 import java.util.ArrayList;
@@ -50,11 +50,11 @@ import javax.xml.bind.annotation.XmlSchemaType;
 import javax.xml.bind.annotation.XmlType;
 
 import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.common.Uri;
+import org.apache.taverna.server.master.common.VersionedElement;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.Listener;
 
 /**
  * This represents <i>all</i> the event listeners attached to a workflow run.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerREST.java
index 161b017..8f58747 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,22 +18,22 @@ package org.taverna.server.master.rest;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.URI_LIST;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_CAPABILITIES;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_NOTIFIERS;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_OP_LIMIT;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_PERM_LIST;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_PERM_WF;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_RUN_LIMIT;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.ROOT;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.RUNS;
-import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.rest.ContentTypes.JSON;
+import static org.apache.taverna.server.master.rest.ContentTypes.URI_LIST;
+import static org.apache.taverna.server.master.rest.ContentTypes.XML;
+import static org.apache.taverna.server.master.rest.TavernaServerREST.PathNames.POL;
+import static org.apache.taverna.server.master.rest.TavernaServerREST.PathNames.POL_CAPABILITIES;
+import static org.apache.taverna.server.master.rest.TavernaServerREST.PathNames.POL_NOTIFIERS;
+import static org.apache.taverna.server.master.rest.TavernaServerREST.PathNames.POL_OP_LIMIT;
+import static org.apache.taverna.server.master.rest.TavernaServerREST.PathNames.POL_PERM_LIST;
+import static org.apache.taverna.server.master.rest.TavernaServerREST.PathNames.POL_PERM_WF;
+import static org.apache.taverna.server.master.rest.TavernaServerREST.PathNames.POL_RUN_LIMIT;
+import static org.apache.taverna.server.master.rest.TavernaServerREST.PathNames.ROOT;
+import static org.apache.taverna.server.master.rest.TavernaServerREST.PathNames.RUNS;
+import static org.apache.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
+import static org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
 
 import java.net.URI;
 import java.util.ArrayList;
@@ -62,17 +62,17 @@ import javax.xml.bind.annotation.XmlValue;
 import org.apache.abdera.model.Entry;
 import org.apache.abdera.model.Feed;
 import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.soap.TavernaServerSOAP;
+import org.apache.taverna.server.master.common.Capability;
+import org.apache.taverna.server.master.common.RunReference;
+import org.apache.taverna.server.master.common.Uri;
+import org.apache.taverna.server.master.common.VersionedElement;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.common.version.Version;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.soap.TavernaServerSOAP;
 
 /**
  * The REST service interface to Taverna 3 Server.
@@ -307,7 +307,7 @@ public interface TavernaServerREST {
 
 		/**
 		 * Gets the maximum number of simultaneous
-		 * {@linkplain org.taverna.server.master.common.Status.Operating
+		 * {@linkplain org.apache.taverna.server.master.common.Status.Operating
 		 * operating} runs that the user may create. The <i>actual</i> number
 		 * they can start may be lower than this. If this number is lower than
 		 * the number they currently have, they will be unable to start any runs

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerRunREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerRunREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerRunREST.java
index ef6ddd4..9a8fa22 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerRunREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerRunREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,34 +20,34 @@ package org.taverna.server.master.rest;
 
 import static javax.ws.rs.core.UriBuilder.fromUri;
 import static org.joda.time.format.ISODateTimeFormat.basicDateTime;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
-import static org.taverna.server.master.interaction.InteractionFeedSupport.FEED_URL_DIR;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.ROBUNDLE;
-import static org.taverna.server.master.rest.ContentTypes.TEXT;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.GENERATE_PROVENANCE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.IN;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LISTEN;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LOG;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.NAME;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.OUT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.PROFILE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.ROOT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.RUNBUNDLE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.SEC;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STATUS;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDERR;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDOUT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_CREATE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_EXPIRE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_FINISH;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_START;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.USAGE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.WF;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
+import static org.apache.taverna.server.master.interaction.InteractionFeedSupport.FEED_URL_DIR;
+import static org.apache.taverna.server.master.rest.ContentTypes.JSON;
+import static org.apache.taverna.server.master.rest.ContentTypes.ROBUNDLE;
+import static org.apache.taverna.server.master.rest.ContentTypes.TEXT;
+import static org.apache.taverna.server.master.rest.ContentTypes.XML;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.GENERATE_PROVENANCE;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.IN;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.LISTEN;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.LOG;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.NAME;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.OUT;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.PROFILE;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.ROOT;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.RUNBUNDLE;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.SEC;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.STATUS;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDERR;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDOUT;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_CREATE;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_EXPIRE;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_FINISH;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_START;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.USAGE;
+import static org.apache.taverna.server.master.rest.TavernaServerRunREST.PathNames.WF;
+import static org.apache.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
 
 import java.net.URI;
 import java.util.ArrayList;
@@ -76,21 +76,21 @@ import javax.xml.bind.annotation.XmlValue;
 
 import org.apache.cxf.jaxrs.model.wadl.Description;
 import org.joda.time.format.DateTimeFormatter;
-import org.taverna.server.master.common.Namespaces;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.NotOwnerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.port_description.OutputDescription;
+import org.apache.taverna.server.master.common.Namespaces;
+import org.apache.taverna.server.master.common.ProfileList;
+import org.apache.taverna.server.master.common.Status;
+import org.apache.taverna.server.master.common.Uri;
+import org.apache.taverna.server.master.common.VersionedElement;
+import org.apache.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.NotOwnerException;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.port_description.OutputDescription;
 
 /**
  * This represents how a Taverna Server workflow run looks to a RESTful API.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerSecurityREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerSecurityREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerSecurityREST.java
index f5101e7..16c1359 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerSecurityREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerSecurityREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,20 +19,20 @@ package org.taverna.server.master.rest;
  */
 
 import static java.util.Collections.emptyList;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.TEXT;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.CREDS;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_CRED;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_PERM;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_TRUST;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.OWNER;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.PERMS;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ROOT;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.TRUSTS;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.rest.ContentTypes.JSON;
+import static org.apache.taverna.server.master.rest.ContentTypes.TEXT;
+import static org.apache.taverna.server.master.rest.ContentTypes.XML;
+import static org.apache.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.CREDS;
+import static org.apache.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_CRED;
+import static org.apache.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_PERM;
+import static org.apache.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_TRUST;
+import static org.apache.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.OWNER;
+import static org.apache.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.PERMS;
+import static org.apache.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ROOT;
+import static org.apache.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.TRUSTS;
 
 import java.net.URI;
 import java.util.ArrayList;
@@ -64,14 +64,14 @@ import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
 import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCredentialException;
+import org.apache.taverna.server.master.common.Credential;
+import org.apache.taverna.server.master.common.Permission;
+import org.apache.taverna.server.master.common.Trust;
+import org.apache.taverna.server.master.common.Uri;
+import org.apache.taverna.server.master.common.VersionedElement;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.InvalidCredentialException;
+import org.apache.taverna.server.master.exceptions.NoCredentialException;
 
 /**
  * Manages the security of the workflow run. In general, only the owner of a run

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/AccessDeniedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/AccessDeniedHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/AccessDeniedHandler.java
index 3418975..76e3bc5 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/AccessDeniedHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/AccessDeniedHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadInputPortNameHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadInputPortNameHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadInputPortNameHandler.java
index a78693d..d147342 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadInputPortNameHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadInputPortNameHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.BadInputPortNameException;
+import org.apache.taverna.server.master.exceptions.BadInputPortNameException;
 
 @Provider
 public class BadInputPortNameHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadPropertyValueHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadPropertyValueHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadPropertyValueHandler.java
index e956749..bc8f0ea 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadPropertyValueHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadPropertyValueHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.BadPropertyValueException;
+import org.apache.taverna.server.master.exceptions.BadPropertyValueException;
 
 @Provider
 public class BadPropertyValueHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadStateChangeHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadStateChangeHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadStateChangeHandler.java
index 53f441b..1246c3b 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadStateChangeHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/BadStateChangeHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
 
 @Provider
 public class BadStateChangeHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/EntryHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/EntryHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/EntryHandler.java
index bc79c22..b852d87 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/EntryHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/EntryHandler.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FeedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FeedHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FeedHandler.java
index 77e7e49..5a31aed 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FeedHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FeedHandler.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileConcatenationHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileConcatenationHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileConcatenationHandler.java
index e0924ad..c610b3b 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileConcatenationHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileConcatenationHandler.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -26,9 +26,9 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyWriter;
 
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.FileConcatenation;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.FileConcatenation;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.interfaces.File;
 
 public class FileConcatenationHandler implements
 		MessageBodyWriter<FileConcatenation> {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileMessageHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileMessageHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileMessageHandler.java
index 7d2b381..0a5f114 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileMessageHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileMessageHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -32,8 +32,8 @@ import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 
 import org.apache.commons.logging.Log;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.interfaces.File;
 
 /**
  * How to write out a File object with JAX-RS.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileSegmentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileSegmentHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileSegmentHandler.java
index 82d5e0a..0c780e0 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileSegmentHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FileSegmentHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -31,8 +31,8 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.rest.FileSegment;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.rest.FileSegment;
 
 /**
  * How to write out a segment of a file with JAX-RS.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FilesystemAccessHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FilesystemAccessHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FilesystemAccessHandler.java
index cfa863c..e5e5bd3 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FilesystemAccessHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/FilesystemAccessHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
 
 @Provider
 public class FilesystemAccessHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/GeneralFailureHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/GeneralFailureHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/GeneralFailureHandler.java
index fe4ba0b..047d8aa 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/GeneralFailureHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/GeneralFailureHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@ import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 
-import org.taverna.server.master.exceptions.GeneralFailureException;
+import org.apache.taverna.server.master.exceptions.GeneralFailureException;
 
 public class GeneralFailureHandler extends HandlerCore implements
 		ExceptionMapper<GeneralFailureException> {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/HandlerCore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/HandlerCore.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/HandlerCore.java
index bc92154..553606f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/HandlerCore.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/HandlerCore.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,7 +25,7 @@ import static org.apache.commons.logging.LogFactory.getLog;
 import javax.ws.rs.core.Response;
 
 import org.apache.commons.logging.Log;
-import org.taverna.server.master.api.ManagementModel;
+import org.apache.taverna.server.master.api.ManagementModel;
 
 /**
  * Base class for handlers that grants Spring-enabled access to the management

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/IllegalArgumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/IllegalArgumentHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/IllegalArgumentHandler.java
index d7ec8f4..8857696 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/IllegalArgumentHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/IllegalArgumentHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ImplementationProblemHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ImplementationProblemHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ImplementationProblemHandler.java
index 806fc67..bee3033 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ImplementationProblemHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ImplementationProblemHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@ import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 
-import org.taverna.server.localworker.remote.ImplementationException;
+import org.apache.taverna.server.localworker.remote.ImplementationException;
 
 public class ImplementationProblemHandler extends HandlerCore implements
 		ExceptionMapper<ImplementationException> {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InputStreamMessageHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InputStreamMessageHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InputStreamMessageHandler.java
index 6b4470b..b082257 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InputStreamMessageHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InputStreamMessageHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InvalidCredentialHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InvalidCredentialHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InvalidCredentialHandler.java
index 7208aa4..54cf970 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InvalidCredentialHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InvalidCredentialHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.apache.taverna.server.master.exceptions.InvalidCredentialException;
 
 @Provider
 public class InvalidCredentialHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/JAXBExceptionHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/JAXBExceptionHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/JAXBExceptionHandler.java
index cf5952e..504b901 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/JAXBExceptionHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/JAXBExceptionHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NegotiationFailedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NegotiationFailedHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NegotiationFailedHandler.java
index 00457fe..be05167 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NegotiationFailedHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NegotiationFailedHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,7 +25,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.rest.TavernaServerDirectoryREST.NegotiationFailedException;
+import org.apache.taverna.server.master.rest.TavernaServerDirectoryREST.NegotiationFailedException;
 
 @Provider
 public class NegotiationFailedHandler implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCreateHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCreateHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCreateHandler.java
index f20f876..d6cc083 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCreateHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCreateHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.NoCreateException;
+import org.apache.taverna.server.master.exceptions.NoCreateException;
 
 @Provider
 public class NoCreateHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCredentialHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCredentialHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCredentialHandler.java
index 6644901..b6260ac 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCredentialHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCredentialHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@ import static javax.ws.rs.core.Response.Status.NOT_FOUND;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 
-import org.taverna.server.master.exceptions.NoCredentialException;
+import org.apache.taverna.server.master.exceptions.NoCredentialException;
 
 public class NoCredentialHandler extends HandlerCore implements
 		ExceptionMapper<NoCredentialException> {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDestroyHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDestroyHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDestroyHandler.java
index 2c0f5a9..fcd980a 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDestroyHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDestroyHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.NoDestroyException;
+import org.apache.taverna.server.master.exceptions.NoDestroyException;
 
 @Provider
 public class NoDestroyHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
index 2f72487..8e4d352 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
 
 @Provider
 public class NoDirectoryEntryHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoListenerHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoListenerHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoListenerHandler.java
index e119b60..ad7fa90 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoListenerHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoListenerHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
 
 @Provider
 public class NoListenerHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoUpdateHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoUpdateHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoUpdateHandler.java
index 2d5dde3..17c1475 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoUpdateHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoUpdateHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
 
 @Provider
 public class NoUpdateHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NotOwnerHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NotOwnerHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NotOwnerHandler.java
index baeb6aa..ab90ebc 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NotOwnerHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NotOwnerHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@ import static javax.ws.rs.core.Response.Status.FORBIDDEN;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 
-import org.taverna.server.master.exceptions.NotOwnerException;
+import org.apache.taverna.server.master.exceptions.NotOwnerException;
 
 public class NotOwnerHandler extends HandlerCore implements
 		ExceptionMapper<NotOwnerException> {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/OverloadedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/OverloadedHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/OverloadedHandler.java
index 9e142f3..951776f 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/OverloadedHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/OverloadedHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.OverloadedException;
+import org.apache.taverna.server.master.exceptions.OverloadedException;
 
 @Provider
 public class OverloadedHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/PermissionHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/PermissionHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/PermissionHandler.java
index d7a4afc..54cee43 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/PermissionHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/PermissionHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -34,7 +34,7 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyReader;
 import javax.ws.rs.ext.MessageBodyWriter;
 
-import org.taverna.server.master.common.Permission;
+import org.apache.taverna.server.master.common.Permission;
 
 /**
  * Handler that allows CXF to send and receive {@linkplain Permission

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/Scufl2DocumentHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
index cf1ccdf..a050c0e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -31,7 +31,7 @@ import javax.ws.rs.ext.MessageBodyReader;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.common.Workflow;
 
 import org.apache.taverna.scufl2.api.io.ReaderException;
 import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/T2FlowDocumentHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
index 1f6d328..2952ee1 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -39,7 +39,7 @@ import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
-import org.taverna.server.master.common.Workflow;
+import org.apache.taverna.server.master.common.Workflow;
 import org.w3c.dom.Document;
 import org.xml.sax.SAXException;
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/URIListHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/URIListHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/URIListHandler.java
index 453ac73..0452074 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/URIListHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/URIListHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,7 +19,7 @@ package org.taverna.server.master.rest.handler;
  */
 
 import static javax.ws.rs.core.Response.status;
-import static org.taverna.server.master.rest.handler.URIListHandler.URI_LIST;
+import static org.apache.taverna.server.master.rest.handler.URIListHandler.URI_LIST;
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/UnknownRunHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/UnknownRunHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/UnknownRunHandler.java
index 4d5c6e8..6751339 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/UnknownRunHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/UnknownRunHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
 
 @Provider
 public class UnknownRunHandler extends HandlerCore implements

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ZipStreamHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ZipStreamHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ZipStreamHandler.java
index 69e526d..ca7a092 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ZipStreamHandler.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ZipStreamHandler.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,7 +19,7 @@ package org.taverna.server.master.rest.handler;
  */
 
 import static org.apache.commons.io.IOUtils.copy;
-import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
+import static org.apache.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -33,7 +33,7 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 
-import org.taverna.server.master.interfaces.Directory.ZipStream;
+import org.apache.taverna.server.master.interfaces.Directory.ZipStream;
 
 /**
  * How to write a ZIP file as the result entity of a request.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/package-info.java
index 8404ead..0ed4b8d 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/package-info.java
@@ -12,7 +12,7 @@
 		@XmlNs(prefix = "port", namespaceURI = DATA),
 		@XmlNs(prefix = "feed", namespaceURI = FEED),
 		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.rest.handler;
+package org.apache.taverna.server.master.rest.handler;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -31,13 +31,13 @@ package org.taverna.server.master.rest.handler;
  */
 
 import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.port_description.Namespaces.DATA;
+import static org.apache.taverna.server.master.common.Namespaces.ADMIN;
+import static org.apache.taverna.server.master.common.Namespaces.FEED;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.port_description.Namespaces.DATA;
 
 import javax.xml.bind.annotation.XmlNs;
 import javax.xml.bind.annotation.XmlSchema;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/package-info.java
index d35dc7b..7397d81 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/package-info.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/package-info.java
@@ -12,7 +12,7 @@
 		@XmlNs(prefix = "port", namespaceURI = DATA),
 		@XmlNs(prefix = "feed", namespaceURI = FEED),
 		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.rest;
+package org.apache.taverna.server.master.rest;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -31,13 +31,13 @@ package org.taverna.server.master.rest;
  */
 
 import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.port_description.Namespaces.DATA;
+import static org.apache.taverna.server.master.common.Namespaces.ADMIN;
+import static org.apache.taverna.server.master.common.Namespaces.FEED;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.apache.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.port_description.Namespaces.DATA;
 
 import javax.xml.bind.annotation.XmlNs;
 import javax.xml.bind.annotation.XmlSchema;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/DirEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/DirEntry.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/DirEntry.java
index 752c6b1..70744c9 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/DirEntry.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/DirEntry.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master.soap;
+package org.apache.taverna.server.master.soap;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.master.soap;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.apache.taverna.server.master.common.Namespaces.XLINK;
 
 import java.net.URI;
 
@@ -29,7 +29,7 @@ import javax.xml.bind.annotation.XmlSchemaType;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
 
-import org.taverna.server.master.common.DirEntryReference;
+import org.apache.taverna.server.master.common.DirEntryReference;
 
 /**
  * A more Taverna-friendly version of the directory entry descriptor classes.



[02/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java
deleted file mode 100644
index f96f91c..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.impl;
-/*
- * 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.
- */
-
-import static java.lang.Runtime.getRuntime;
-import static java.lang.System.getProperty;
-import static java.lang.System.out;
-import static java.lang.management.ManagementFactory.getRuntimeMXBean;
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-import static java.util.UUID.randomUUID;
-import static org.apache.commons.io.FileUtils.forceDelete;
-import static org.apache.commons.io.FileUtils.forceMkdir;
-import static org.apache.commons.io.FileUtils.writeByteArrayToFile;
-import static org.apache.commons.io.FileUtils.writeLines;
-import static org.taverna.server.localworker.api.Constants.HELIO_TOKEN_NAME;
-import static org.taverna.server.localworker.api.Constants.KEYSTORE_FILE;
-import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
-import static org.taverna.server.localworker.api.Constants.SECURITY_DIR_NAME;
-import static org.taverna.server.localworker.api.Constants.SHARED_DIR_PROP;
-import static org.taverna.server.localworker.api.Constants.SUBDIR_LIST;
-import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
-import static org.taverna.server.localworker.api.Constants.TRUSTSTORE_FILE;
-import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedFile;
-import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
-import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
-import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
-import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URL;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.UUID;
-
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.api.WorkerFactory;
-import org.taverna.server.localworker.remote.IllegalStateTransitionException;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteInput;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteSecurityContext;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.remote.StillWorkingOnItException;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-
-/**
- * This class implements one side of the connection between the Taverna Server
- * master server and this process. It delegates to a {@link Worker} instance the
- * handling of actually running a workflow.
- * 
- * @author Donal Fellows
- * @see DirectoryDelegate
- * @see FileDelegate
- * @see WorkerCore
- */
-@SuppressWarnings("serial")
-public class LocalWorker extends UnicastRemoteObject implements RemoteSingleRun {
-	// ----------------------- CONSTANTS -----------------------
-
-	/** Handle to the directory containing the security info. */
-	static final File SECURITY_DIR;
-	static final String SLASHTEMP;
-	static {
-		SLASHTEMP = getProperty("java.io.tmpdir");
-		File home = new File(getProperty("user.home"));
-		// If we can't write to $HOME (i.e., we're in an odd deployment) use
-		// the official version of /tmp/$PID as a fallback.
-		if (!home.canWrite())
-			home = new File(SLASHTEMP, getRuntimeMXBean().getName());
-		SECURITY_DIR = new File(home, SECURITY_DIR_NAME);
-	}
-
-	// ----------------------- VARIABLES -----------------------
-
-	/**
-	 * Magic flag used to turn off problematic code when testing inside CI
-	 * environment.
-	 */
-	static boolean DO_MKDIR = true;
-
-	/** What to use to run a workflow engine. */
-	private final String executeWorkflowCommand;
-	/** What workflow to run. */
-	private final byte[] workflow;
-	/** The remote access object for the working directory. */
-	private final DirectoryDelegate baseDir;
-	/** What inputs to pass as files. */
-	final Map<String, String> inputFiles;
-	/** What inputs to pass as files (as file refs). */
-	final Map<String, File> inputRealFiles;
-	/** What inputs to pass as direct values. */
-	final Map<String, String> inputValues;
-	/** What delimiters to use. */
-	final Map<String, String> inputDelimiters;
-	/** The interface to the workflow engine subprocess. */
-	private final Worker core;
-	/** Our descriptor token (UUID). */
-	private final String masterToken;
-	/**
-	 * The root working directory for a workflow run, or <tt>null</tt> if it has
-	 * been deleted.
-	 */
-	private File base;
-	/**
-	 * When did this workflow start running, or <tt>null</tt> for
-	 * "never/not yet".
-	 */
-	private Date start;
-	/**
-	 * When did this workflow finish running, or <tt>null</tt> for
-	 * "never/not yet".
-	 */
-	private Date finish;
-	/** The cached status of the workflow run. */
-	RemoteStatus status;
-	/**
-	 * The name of the input Baclava document, or <tt>null</tt> to not do it
-	 * that way.
-	 */
-	String inputBaclava;
-	/**
-	 * The name of the output Baclava document, or <tt>null</tt> to not do it
-	 * that way.
-	 */
-	String outputBaclava;
-	/**
-	 * The file containing the input Baclava document, or <tt>null</tt> to not
-	 * do it that way.
-	 */
-	private File inputBaclavaFile;
-	/**
-	 * The file containing the output Baclava document, or <tt>null</tt> to not
-	 * do it that way.
-	 */
-	private File outputBaclavaFile;
-	/**
-	 * Registered shutdown hook so that we clean up when this process is killed
-	 * off, or <tt>null</tt> if that is no longer necessary.
-	 */
-	Thread shutdownHook;
-	/** Location for security information to be written to. */
-	File securityDirectory;
-	/**
-	 * Password to use to encrypt security information.
-	 */
-	char[] keystorePassword = KEYSTORE_PASSWORD;
-	/** Additional server-specified environment settings. */
-	Map<String, String> environment = new HashMap<>();
-	/** Additional server-specified java runtime settings. */
-	List<String> runtimeSettings = new ArrayList<>();
-	URL interactionFeedURL;
-	URL webdavURL;
-	URL publishURL;//FIXME
-	private boolean doProvenance = true;
-
-	// ----------------------- METHODS -----------------------
-
-	/**
-	 * @param executeWorkflowCommand
-	 *            The script used to execute workflows.
-	 * @param workflow
-	 *            The workflow to execute.
-	 * @param workerClass
-	 *            The class to instantiate as our local representative of the
-	 *            run.
-	 * @param urReceiver
-	 *            The remote class to report the generated usage record(s) to.
-	 * @param id
-	 *            The UUID to use, or <tt>null</tt> if we are to invent one.
-	 * @param seedEnvironment
-	 *            The key/value pairs to seed the worker subprocess environment
-	 *            with.
-	 * @param javaParams
-	 *            Parameters to pass to the worker subprocess java runtime
-	 *            itself.
-	 * @param workerFactory
-	 *            How to make instances of the low-level worker objects.
-	 * @throws RemoteException
-	 *             If registration of the worker fails.
-	 * @throws ImplementationException
-	 *             If something goes wrong during local setup.
-	 */
-	protected LocalWorker(String executeWorkflowCommand, byte[] workflow,
-			UsageRecordReceiver urReceiver, UUID id,
-			Map<String, String> seedEnvironment, List<String> javaParams,
-			WorkerFactory workerFactory) throws RemoteException,
-			ImplementationException {
-		super();
-		if (id == null)
-			id = randomUUID();
-		masterToken = id.toString();
-		this.workflow = workflow;
-		this.executeWorkflowCommand = executeWorkflowCommand;
-		String sharedDir = getProperty(SHARED_DIR_PROP, SLASHTEMP);
-		base = new File(sharedDir, masterToken);
-		out.println("about to create " + base);
-		try {
-			forceMkdir(base);
-			for (String subdir : SUBDIR_LIST) {
-				new File(base, subdir).mkdir();
-			}
-		} catch (IOException e) {
-			throw new ImplementationException(
-					"problem creating run working directory", e);
-		}
-		baseDir = new DirectoryDelegate(base, null);
-		inputFiles = new HashMap<>();
-		inputRealFiles = new HashMap<>();
-		inputValues = new HashMap<>();
-		inputDelimiters = new HashMap<>();
-		environment.putAll(seedEnvironment);
-		runtimeSettings.addAll(javaParams);
-		try {
-			core = workerFactory.makeInstance();
-		} catch (Exception e) {
-			out.println("problem when creating core worker implementation");
-			e.printStackTrace(out);
-			throw new ImplementationException(
-					"problem when creating core worker implementation", e);
-		}
-		core.setURReceiver(urReceiver);
-		Thread t = new Thread(new Runnable() {
-			/**
-			 * Kill off the worker launched by the core.
-			 */
-			@Override
-			public void run() {
-				try {
-					shutdownHook = null;
-					destroy();
-				} catch (ImplementationException e) {
-					// Absolutely nothing we can do here
-				}
-			}
-		});
-		getRuntime().addShutdownHook(t);
-		shutdownHook = t;
-		status = Initialized;
-	}
-
-	@Override
-	public void destroy() throws ImplementationException {
-		killWorkflowSubprocess();
-		removeFromShutdownHooks();
-		// Is this it?
-		deleteWorkingDirectory();
-		deleteSecurityManagerDirectory();
-		core.deleteLocalResources();
-	}
-
-	private void killWorkflowSubprocess() {
-		if (status != Finished && status != Initialized)
-			try {
-				core.killWorker();
-				if (finish == null)
-					finish = new Date();
-			} catch (Exception e) {
-				out.println("problem when killing worker");
-				e.printStackTrace(out);
-			}
-	}
-
-	private void removeFromShutdownHooks() throws ImplementationException {
-		try {
-			if (shutdownHook != null)
-				getRuntime().removeShutdownHook(shutdownHook);
-		} catch (RuntimeException e) {
-			throw new ImplementationException("problem removing shutdownHook",
-					e);
-		} finally {
-			shutdownHook = null;
-		}
-	}
-
-	private void deleteWorkingDirectory() throws ImplementationException {
-		try {
-			if (base != null)
-				forceDelete(base);
-		} catch (IOException e) {
-			out.println("problem deleting working directory");
-			e.printStackTrace(out);
-			throw new ImplementationException(
-					"problem deleting working directory", e);
-		} finally {
-			base = null;
-		}
-	}
-
-	private void deleteSecurityManagerDirectory()
-			throws ImplementationException {
-		try {
-			if (securityDirectory != null)
-				forceDelete(securityDirectory);
-		} catch (IOException e) {
-			out.println("problem deleting security directory");
-			e.printStackTrace(out);
-			throw new ImplementationException(
-					"problem deleting security directory", e);
-		} finally {
-			securityDirectory = null;
-		}
-	}
-
-	@Override
-	public void addListener(RemoteListener listener) throws RemoteException,
-			ImplementationException {
-		throw new ImplementationException("not implemented");
-	}
-
-	@Override
-	public String getInputBaclavaFile() {
-		return inputBaclava;
-	}
-
-	@Override
-	public List<RemoteInput> getInputs() throws RemoteException {
-		ArrayList<RemoteInput> result = new ArrayList<>();
-		for (String name : inputFiles.keySet())
-			result.add(new InputDelegate(name));
-		return result;
-	}
-
-	@Override
-	public List<String> getListenerTypes() {
-		return emptyList();
-	}
-
-	@Override
-	public List<RemoteListener> getListeners() {
-		return singletonList(core.getDefaultListener());
-	}
-
-	@Override
-	public String getOutputBaclavaFile() {
-		return outputBaclava;
-	}
-
-	class SecurityDelegate extends UnicastRemoteObject implements
-			RemoteSecurityContext {
-		private void setPrivatePerms(File dir) {
-			if (!dir.setReadable(false, false) || !dir.setReadable(true, true)
-					|| !dir.setExecutable(false, false)
-					|| !dir.setExecutable(true, true)
-					|| !dir.setWritable(false, false)
-					|| !dir.setWritable(true, true)) {
-				out.println("warning: "
-						+ "failed to set permissions on security context directory");
-			}
-		}
-
-		protected SecurityDelegate(String token) throws IOException {
-			super();
-			if (DO_MKDIR) {
-				securityDirectory = new File(SECURITY_DIR, token);
-				forceMkdir(securityDirectory);
-				setPrivatePerms(securityDirectory);
-			}
-		}
-
-		/**
-		 * Write some data to a given file in the context directory.
-		 * 
-		 * @param name
-		 *            The name of the file to write.
-		 * @param data
-		 *            The bytes to put in the file.
-		 * @throws RemoteException
-		 *             If anything goes wrong.
-		 * @throws ImplementationException
-		 */
-		protected void write(String name, byte[] data) throws RemoteException,
-				ImplementationException {
-			try {
-				File f = new File(securityDirectory, name);
-				writeByteArrayToFile(f, data);
-			} catch (IOException e) {
-				throw new ImplementationException("problem writing " + name, e);
-			}
-		}
-
-		/**
-		 * Write some data to a given file in the context directory.
-		 * 
-		 * @param name
-		 *            The name of the file to write.
-		 * @param data
-		 *            The lines to put in the file. The
-		 *            {@linkplain LocalWorker#SYSTEM_ENCODING system encoding}
-		 *            will be used to do the writing.
-		 * @throws RemoteException
-		 *             If anything goes wrong.
-		 * @throws ImplementationException
-		 */
-		protected void write(String name, Collection<String> data)
-				throws RemoteException, ImplementationException {
-			try {
-				File f = new File(securityDirectory, name);
-				writeLines(f, SYSTEM_ENCODING, data);
-			} catch (IOException e) {
-				throw new ImplementationException("problem writing " + name, e);
-			}
-		}
-
-		/**
-		 * Write some data to a given file in the context directory.
-		 * 
-		 * @param name
-		 *            The name of the file to write.
-		 * @param data
-		 *            The line to put in the file. The
-		 *            {@linkplain LocalWorker#SYSTEM_ENCODING system encoding}
-		 *            will be used to do the writing.
-		 * @throws RemoteException
-		 *             If anything goes wrong.
-		 * @throws ImplementationException
-		 */
-		protected void write(String name, char[] data) throws RemoteException,
-				ImplementationException {
-			try {
-				File f = new File(securityDirectory, name);
-				writeLines(f, SYSTEM_ENCODING, asList(new String(data)));
-			} catch (IOException e) {
-				throw new ImplementationException("problem writing " + name, e);
-			}
-		}
-
-		@Override
-		public void setKeystore(byte[] keystore) throws RemoteException,
-				ImplementationException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			if (keystore == null)
-				throw new IllegalArgumentException("keystore may not be null");
-			write(KEYSTORE_FILE, keystore);
-		}
-
-		@Override
-		public void setPassword(char[] password) throws RemoteException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			if (password == null)
-				throw new IllegalArgumentException("password may not be null");
-			keystorePassword = password.clone();
-		}
-
-		@Override
-		public void setTruststore(byte[] truststore) throws RemoteException,
-				ImplementationException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			if (truststore == null)
-				throw new IllegalArgumentException("truststore may not be null");
-			write(TRUSTSTORE_FILE, truststore);
-		}
-
-		@Override
-		public void setUriToAliasMap(Map<URI, String> uriToAliasMap)
-				throws RemoteException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			if (uriToAliasMap == null)
-				return;
-			ArrayList<String> lines = new ArrayList<>();
-			for (Entry<URI, String> site : uriToAliasMap.entrySet())
-				lines.add(site.getKey().toASCIIString() + " " + site.getValue());
-			// write(URI_ALIAS_MAP, lines);
-		}
-
-		@Override
-		public void setHelioToken(String helioToken) throws RemoteException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			out.println("registering HELIO CIS token for export");
-			environment.put(HELIO_TOKEN_NAME, helioToken);
-		}
-	}
-
-	@Override
-	public RemoteSecurityContext getSecurityContext() throws RemoteException,
-			ImplementationException {
-		try {
-			return new SecurityDelegate(masterToken);
-		} catch (RemoteException e) {
-			if (e.getCause() != null)
-				throw new ImplementationException(
-						"problem initializing security context", e.getCause());
-			throw e;
-		} catch (IOException e) {
-			throw new ImplementationException(
-					"problem initializing security context", e);
-		}
-	}
-
-	@Override
-	public RemoteStatus getStatus() {
-		// only state that can spontaneously change to another
-		if (status == Operating) {
-			status = core.getWorkerStatus();
-			if (status == Finished && finish == null)
-				finish = new Date();
-		}
-		return status;
-	}
-
-	@Override
-	public RemoteDirectory getWorkingDirectory() {
-		return baseDir;
-	}
-
-	File validateFilename(String filename) throws RemoteException {
-		if (filename == null)
-			throw new IllegalArgumentException("filename must be non-null");
-		try {
-			return getValidatedFile(base, filename.split("/"));
-		} catch (IOException e) {
-			throw new IllegalArgumentException("failed to validate filename", e);
-		}
-	}
-
-	class InputDelegate extends UnicastRemoteObject implements RemoteInput {
-		private String name;
-
-		InputDelegate(String name) throws RemoteException {
-			super();
-			this.name = name;
-			if (!inputFiles.containsKey(name)) {
-				if (status != Initialized)
-					throw new IllegalStateException("not initializing");
-				inputFiles.put(name, null);
-				inputRealFiles.put(name, null);
-				inputValues.put(name, null);
-				inputDelimiters.put(name, null);
-			}
-		}
-
-		@Override
-		public String getFile() {
-			return inputFiles.get(name);
-		}
-
-		@Override
-		public String getName() {
-			return name;
-		}
-
-		@Override
-		public String getValue() {
-			return inputValues.get(name);
-		}
-
-		@Override
-		public String getDelimiter() throws RemoteException {
-			return inputDelimiters.get(name);
-		}
-
-		@Override
-		public void setFile(String file) throws RemoteException {
-			if (status != Initialized)
-				throw new IllegalStateException("not initializing");
-			inputRealFiles.put(name, validateFilename(file));
-			inputValues.put(name, null);
-			inputFiles.put(name, file);
-			inputBaclava = null;
-		}
-
-		@Override
-		public void setValue(String value) throws RemoteException {
-			if (status != Initialized)
-				throw new IllegalStateException("not initializing");
-			inputValues.put(name, value);
-			inputFiles.put(name, null);
-			inputRealFiles.put(name, null);
-			inputBaclava = null;
-		}
-
-		@Override
-		public void setDelimiter(String delimiter) throws RemoteException {
-			if (status != Initialized)
-				throw new IllegalStateException("not initializing");
-			if (inputBaclava != null)
-				throw new IllegalStateException("input baclava file set");
-			if (delimiter != null) {
-				if (delimiter.length() > 1)
-					throw new IllegalStateException(
-							"multi-character delimiter not permitted");
-				if (delimiter.charAt(0) == 0)
-					throw new IllegalStateException(
-							"may not use NUL for splitting");
-				if (delimiter.charAt(0) > 127)
-					throw new IllegalStateException(
-							"only ASCII characters supported for splitting");
-			}
-			inputDelimiters.put(name, delimiter);
-		}
-	}
-
-	@Override
-	public RemoteInput makeInput(String name) throws RemoteException {
-		return new InputDelegate(name);
-	}
-
-	@Override
-	public RemoteListener makeListener(String type, String configuration)
-			throws RemoteException {
-		throw new RemoteException("listener manufacturing unsupported");
-	}
-
-	@Override
-	public void setInputBaclavaFile(String filename) throws RemoteException {
-		if (status != Initialized)
-			throw new IllegalStateException("not initializing");
-		inputBaclavaFile = validateFilename(filename);
-		for (String input : inputFiles.keySet()) {
-			inputFiles.put(input, null);
-			inputRealFiles.put(input, null);
-			inputValues.put(input, null);
-		}
-		inputBaclava = filename;
-	}
-
-	@Override
-	public void setOutputBaclavaFile(String filename) throws RemoteException {
-		if (status != Initialized)
-			throw new IllegalStateException("not initializing");
-		if (filename != null)
-			outputBaclavaFile = validateFilename(filename);
-		else
-			outputBaclavaFile = null;
-		outputBaclava = filename;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean prov) {
-		doProvenance = prov;
-	}
-
-	@Override
-	public void setStatus(RemoteStatus newStatus)
-			throws IllegalStateTransitionException, RemoteException,
-			ImplementationException, StillWorkingOnItException {
-		if (status == newStatus)
-			return;
-
-		switch (newStatus) {
-		case Initialized:
-			throw new IllegalStateTransitionException(
-					"may not move back to start");
-		case Operating:
-			switch (status) {
-			case Initialized:
-				boolean started;
-				try {
-					started = createWorker();
-				} catch (Exception e) {
-					throw new ImplementationException(
-							"problem creating executing workflow", e);
-				}
-				if (!started)
-					throw new StillWorkingOnItException(
-							"workflow start in process");
-				break;
-			case Stopped:
-				try {
-					core.startWorker();
-				} catch (Exception e) {
-					throw new ImplementationException(
-							"problem continuing workflow run", e);
-				}
-				break;
-			case Finished:
-				throw new IllegalStateTransitionException("already finished");
-			default:
-				break;
-			}
-			status = Operating;
-			break;
-		case Stopped:
-			switch (status) {
-			case Initialized:
-				throw new IllegalStateTransitionException(
-						"may only stop from Operating");
-			case Operating:
-				try {
-					core.stopWorker();
-				} catch (Exception e) {
-					throw new ImplementationException(
-							"problem stopping workflow run", e);
-				}
-				break;
-			case Finished:
-				throw new IllegalStateTransitionException("already finished");
-			default:
-				break;
-			}
-			status = Stopped;
-			break;
-		case Finished:
-			switch (status) {
-			case Operating:
-			case Stopped:
-				try {
-					core.killWorker();
-					if (finish == null)
-						finish = new Date();
-				} catch (Exception e) {
-					throw new ImplementationException(
-							"problem killing workflow run", e);
-				}
-			default:
-				break;
-			}
-			status = Finished;
-			break;
-		}
-	}
-
-	private boolean createWorker() throws Exception {
-		start = new Date();
-		char[] pw = keystorePassword;
-		keystorePassword = null;
-		/*
-		 * Do not clear the keystorePassword array here; its ownership is
-		 * *transferred* to the worker core which doesn't copy it but *does*
-		 * clear it after use.
-		 */
-		return core.initWorker(this, executeWorkflowCommand, workflow, base,
-				inputBaclavaFile, inputRealFiles, inputValues, inputDelimiters,
-				outputBaclavaFile, securityDirectory, pw, doProvenance,
-				environment, masterToken, runtimeSettings);
-	}
-
-	@Override
-	public Date getFinishTimestamp() {
-		return finish == null ? null : new Date(finish.getTime());
-	}
-
-	@Override
-	public Date getStartTimestamp() {
-		return start == null ? null : new Date(start.getTime());
-	}
-
-	@Override
-	public void setInteractionServiceDetails(URL feed, URL webdav, URL publish) {
-		interactionFeedURL = feed;
-		webdavURL = webdav;
-		publishURL = publish;
-	}
-
-	@Override
-	public void ping() {
-		// Do nothing here; this *should* be empty
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java
deleted file mode 100644
index 167302c..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.impl;
-/*
- * 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.
- */
-
-import static java.lang.Runtime.getRuntime;
-import static java.lang.System.exit;
-import static java.lang.System.getProperty;
-import static java.lang.System.out;
-import static java.lang.System.setProperty;
-import static java.lang.System.setSecurityManager;
-import static java.rmi.registry.LocateRegistry.getRegistry;
-import static org.taverna.server.localworker.api.Constants.DEATH_DELAY;
-import static org.taverna.server.localworker.api.Constants.LOCALHOST;
-import static org.taverna.server.localworker.api.Constants.RMI_HOST_PROP;
-import static org.taverna.server.localworker.api.Constants.SECURITY_POLICY_FILE;
-import static org.taverna.server.localworker.api.Constants.SEC_POLICY_PROP;
-import static org.taverna.server.localworker.api.Constants.UNSECURE_PROP;
-
-import java.io.ByteArrayInputStream;
-import java.net.URI;
-import java.rmi.RemoteException;
-import java.rmi.registry.Registry;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
-import org.taverna.server.localworker.api.RunAccounting;
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.api.WorkerFactory;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-
-/**
- * The registered factory for runs, this class is responsible for constructing
- * runs that are suitable for particular users. It is also the entry point for
- * this whole process.
- * 
- * @author Donal Fellows
- * @see LocalWorker
- */
-@SuppressWarnings("serial")
-public class TavernaRunManager extends UnicastRemoteObject implements
-		RemoteRunFactory, RunAccounting, WorkerFactory {
-	String command;
-	Map<String, String> seedEnvironment = new HashMap<>();
-	List<String> javaInitParams = new ArrayList<>();
-	private WorkflowBundleIO io;
-	private int activeRuns = 0;
-	// Hacks!
-	public static String interactionHost;
-	public static String interactionPort;
-	public static String interactionWebdavPath;
-	public static String interactionFeedPath;
-
-	/**
-	 * How to get the actual workflow document from the XML document that it is
-	 * contained in.
-	 * 
-	 * @param containerDocument
-	 *            The document sent from the web interface.
-	 * @return The element describing the workflow, as expected by the Taverna
-	 *         command line executor.
-	 */
-	protected Element unwrapWorkflow(Document containerDocument) {
-		return (Element) containerDocument.getDocumentElement().getFirstChild();
-	}
-
-	private static final String usage = "java -jar server.worker.jar workflowExecScript ?-Ekey=val...? ?-Jconfig? UUID";
-
-	/**
-	 * An RMI-enabled factory for runs.
-	 * 
-	 * @param command
-	 *            What command to call to actually run a run.
-	 * @throws RemoteException
-	 *             If anything goes wrong during creation of the instance.
-	 */
-	public TavernaRunManager(String command) throws RemoteException {
-		this.command = command;
-		this.io = new WorkflowBundleIO();
-	}
-
-	@Override
-	public RemoteSingleRun make(byte[] workflow, String creator,
-			UsageRecordReceiver urReceiver, UUID id) throws RemoteException {
-		if (creator == null)
-			throw new RemoteException("no creator");
-		try {
-			URI wfid = io.readBundle(new ByteArrayInputStream(workflow), null)
-					.getMainWorkflow().getIdentifier();
-			out.println("Creating run from workflow <" + wfid + "> for <"
-					+ creator + ">");
-			return new LocalWorker(command, workflow, urReceiver, id,
-					seedEnvironment, javaInitParams, this);
-		} catch (RemoteException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new RemoteException("bad instance construction", e);
-		}
-	}
-
-	private static boolean shuttingDown;
-	private static String factoryName;
-	private static Registry registry;
-
-	static synchronized void unregisterFactory() {
-		if (!shuttingDown) {
-			shuttingDown = true;
-			try {
-				if (factoryName != null && registry != null)
-					registry.unbind(factoryName);
-			} catch (Exception e) {
-				e.printStackTrace(out);
-			}
-		}
-	}
-
-	@Override
-	public void shutdown() {
-		unregisterFactory();
-		new Thread(new DelayedDeath()).start();
-	}
-
-	static class DelayedDeath implements Runnable {
-		@Override
-		public void run() {
-			try {
-				Thread.sleep(DEATH_DELAY);
-			} catch (InterruptedException e) {
-			} finally {
-				exit(0);
-			}
-		}
-	}
-
-	private void addArgument(String arg) {
-		if (arg.startsWith("-E")) {
-			String trimmed = arg.substring(2);
-			int idx = trimmed.indexOf('=');
-			if (idx > 0) {
-				addEnvironmentDefinition(trimmed.substring(0, idx),
-						trimmed.substring(idx + 1));
-				return;
-			}
-		} else if (arg.startsWith("-D")) {
-			if (arg.indexOf('=') > 0) {
-				addJavaParameter(arg);
-				return;
-			}
-		} else if (arg.startsWith("-J")) {
-			addJavaParameter(arg.substring(2));
-			return;
-		}
-		throw new IllegalArgumentException("argument \"" + arg
-				+ "\" must start with -D, -E or -J; "
-				+ "-D and -E must contain a \"=\"");
-	}
-
-	/**
-	 * @param args
-	 *            The arguments from the command line invocation.
-	 * @throws Exception
-	 *             If we can't connect to the RMI registry, or if we can't read
-	 *             the workflow, or if we can't build the worker instance, or
-	 *             register it. Also if the arguments are wrong.
-	 */
-	public static void main(String[] args) throws Exception {
-		if (args.length < 2)
-			throw new Exception("wrong # args: must be \"" + usage + "\"");
-		if (!getProperty(UNSECURE_PROP, "no").equals("yes")) {
-			setProperty(SEC_POLICY_PROP, LocalWorker.class.getClassLoader()
-					.getResource(SECURITY_POLICY_FILE).toExternalForm());
-			setProperty(RMI_HOST_PROP, LOCALHOST);
-		}
-		setSecurityManager(new SecurityManager());
-		factoryName = args[args.length - 1];
-		TavernaRunManager man = new TavernaRunManager(args[0]);
-		for (int i = 1; i < args.length - 1; i++)
-			man.addArgument(args[i]);
-		registry = getRegistry(LOCALHOST);
-
-		registry.bind(factoryName, man);
-		getRuntime().addShutdownHook(new Thread() {
-			@Override
-			public void run() {
-				unregisterFactory();
-			}
-		});
-		out.println("registered RemoteRunFactory with ID " + factoryName);
-	}
-
-	private void addJavaParameter(String string) {
-		this.javaInitParams.add(string);
-	}
-
-	private void addEnvironmentDefinition(String key, String value) {
-		this.seedEnvironment.put(key, value);
-	}
-
-	@Override
-	public void setInteractionServiceDetails(String host, String port,
-			String webdavPath, String feedPath) throws RemoteException {
-		if (host == null || port == null || webdavPath == null
-				|| feedPath == null)
-			throw new IllegalArgumentException("all params must be non-null");
-		interactionHost = host;
-		interactionPort = port;
-		interactionWebdavPath = webdavPath;
-		interactionFeedPath = feedPath;
-	}
-
-	@Override
-	public synchronized int countOperatingRuns() {
-		return (activeRuns < 0 ? 0 : activeRuns);
-	}
-
-	@Override
-	public synchronized void runStarted() {
-		activeRuns++;
-	}
-
-	@Override
-	public synchronized void runCeased() {
-		activeRuns--;
-	}
-
-	@Override
-	public Worker makeInstance() throws Exception {
-		return new WorkerCore(this);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java
deleted file mode 100644
index 4aa6605..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java
+++ /dev/null
@@ -1,931 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.impl;
-/*
- * 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.
- */
-
-import static java.io.File.createTempFile;
-import static java.io.File.pathSeparator;
-import static java.lang.Boolean.parseBoolean;
-import static java.lang.Double.parseDouble;
-import static java.lang.Integer.parseInt;
-import static java.lang.Long.parseLong;
-import static java.lang.Runtime.getRuntime;
-import static java.lang.System.out;
-import static java.net.InetAddress.getLocalHost;
-import static org.apache.commons.io.FileUtils.forceDelete;
-import static org.apache.commons.io.FileUtils.sizeOfDirectory;
-import static org.apache.commons.io.FileUtils.write;
-import static org.apache.commons.io.IOUtils.copy;
-import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_DIRECTORY;
-import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_PASSWORD;
-import static org.taverna.server.localworker.api.Constants.DEATH_TIME;
-import static org.taverna.server.localworker.api.Constants.DEFAULT_LISTENER_NAME;
-import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
-import static org.taverna.server.localworker.api.Constants.START_WAIT_TIME;
-import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
-import static org.taverna.server.localworker.api.Constants.TIME;
-import static org.taverna.server.localworker.impl.Status.Aborted;
-import static org.taverna.server.localworker.impl.Status.Completed;
-import static org.taverna.server.localworker.impl.Status.Failed;
-import static org.taverna.server.localworker.impl.Status.Held;
-import static org.taverna.server.localworker.impl.Status.Started;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionFeedPath;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionHost;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionPort;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionWebdavPath;
-import static org.taverna.server.localworker.impl.WorkerCore.pmap;
-import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
-import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
-import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
-import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.xml.datatype.DatatypeConfigurationException;
-import javax.xml.ws.Holder;
-
-import org.apache.taverna.server.usagerecord.JobUsageRecord;
-import org.taverna.server.localworker.api.RunAccounting;
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.impl.utils.TimingOutTask;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-
-/**
- * The core class that connects to a Taverna command-line workflow execution
- * engine. This implementation always registers a single listener, &lquo;
- * <tt>io</tt> &rquo;, with two properties representing the stdout and stderr of
- * the run and one representing the exit code. The listener is
- * remote-accessible. It does not support attaching any other listeners.
- * 
- * @author Donal Fellows
- */
-@SuppressWarnings("serial")
-public class WorkerCore extends UnicastRemoteObject implements Worker,
-		RemoteListener {
-	@Nonnull
-	static final Map<String, Property> pmap = new HashMap<>();
-	/**
-	 * Regular expression to extract the detailed timing information from the
-	 * output of /usr/bin/time
-	 */
-	@Nonnull
-	private static final Pattern TimeRE;
-	static {
-		final String TIMERE = "([0-9.:]+)";
-		final String TERMS = "(real|user|system|sys|elapsed)";
-		TimeRE = Pattern.compile(TIMERE + " *" + TERMS + "[ \t]*" + TIMERE
-				+ " *" + TERMS + "[ \t]*" + TIMERE + " *" + TERMS);
-	}
-
-	/**
-	 * Environment variables to remove before any fork (because they're large or
-	 * potentially leaky).
-	 */
-	// TODO Conduct a proper survey of what to remove
-	@Nonnull
-	private static final String[] ENVIRONMENT_TO_REMOVE = { "SUDO_COMMAND",
-			"SUDO_USER", "SUDO_GID", "SUDO_UID", "DISPLAY", "LS_COLORS",
-			"XFILESEARCHPATH", "SSH_AGENT_PID", "SSH_AUTH_SOCK" };
-
-	@Nullable
-	Process subprocess;
-	@Nonnull
-	final StringWriter stdout;
-	@Nonnull
-	final StringWriter stderr;
-	@Nullable
-	Integer exitCode;
-	boolean readyToSendEmail;
-	@Nullable
-	String emailAddress;
-	@Nullable
-	Date start;
-	@Nonnull
-	final RunAccounting accounting;
-	@Nonnull
-	final Holder<Integer> pid;
-
-	private boolean finished;
-	@Nullable
-	private JobUsageRecord ur;
-	@Nullable
-	private File wd;
-	@Nullable
-	private UsageRecordReceiver urreceiver;
-	@Nullable
-	private File workflowFile;
-	private boolean stopped;
-
-	/**
-	 * @param accounting
-	 *            Object that looks after how many runs are executing.
-	 * @throws RemoteException
-	 */
-	public WorkerCore(@Nonnull RunAccounting accounting) throws RemoteException {
-		super();
-		stdout = new StringWriter();
-		stderr = new StringWriter();
-		pid = new Holder<>();
-		this.accounting = accounting;
-	}
-
-	private int getPID() {
-		synchronized (pid) {
-			if (pid.value == null)
-				return -1;
-			return pid.value;
-		}
-	}
-
-	/**
-	 * Fire up the workflow. This causes a transition into the operating state.
-	 * 
-	 * @param executeWorkflowCommand
-	 *            The command to run to execute the workflow.
-	 * @param workflow
-	 *            The workflow document to execute.
-	 * @param workingDir
-	 *            What directory to use as the working directory.
-	 * @param inputBaclava
-	 *            The baclava file to use for inputs, or <tt>null</tt> to use
-	 *            the other <b>input*</b> arguments' values.
-	 * @param inputFiles
-	 *            A mapping of input names to files that supply them. Note that
-	 *            we assume that nothing mapped here will be mapped in
-	 *            <b>inputValues</b>.
-	 * @param inputValues
-	 *            A mapping of input names to values to supply to them. Note
-	 *            that we assume that nothing mapped here will be mapped in
-	 *            <b>inputFiles</b>.
-	 * @param outputBaclava
-	 *            What baclava file to write the output from the workflow into,
-	 *            or <tt>null</tt> to have it written into the <tt>out</tt>
-	 *            subdirectory.
-	 * @param token
-	 *            The name of the workflow run.
-	 * @return <tt>true</tt> if the worker started, or <tt>false</tt> if a
-	 *         timeout occurred.
-	 * @throws IOException
-	 *             If any of quite a large number of things goes wrong.
-	 */
-	@Override
-	public boolean initWorker(
-			@Nonnull final LocalWorker local,
-			@Nonnull final String executeWorkflowCommand,
-			@Nonnull final byte[] workflow,
-			@Nonnull final File workingDir,
-			@Nullable final File inputBaclava,
-			@Nonnull final Map<String, File> inputFiles,
-			@Nonnull final Map<String, String> inputValues, 
-			@Nonnull final Map<String, String> inputDelimiters,
-			@Nullable final File outputBaclava,
-			@Nonnull final File securityDir,
-			@Nullable final char[] password,
-			final boolean generateProvenance,
-			@Nonnull final Map<String, String> environment,
-			@Nullable final String token,
-			@Nonnull final List<String> runtime) throws IOException {
-		try {
-			new TimingOutTask() {
-				@Override
-				public void doIt() throws IOException {
-					startExecutorSubprocess(
-							createProcessBuilder(local, executeWorkflowCommand,
-									workflow, workingDir, inputBaclava,
-									inputFiles, inputValues, inputDelimiters,
-									outputBaclava, securityDir, password,
-									generateProvenance, environment, token,
-									runtime), password);
-				}
-			}.doOrTimeOut(START_WAIT_TIME);
-		} catch (IOException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new IOException(e);
-		}
-		return subprocess != null;
-	}
-
-	private void startExecutorSubprocess(@Nonnull ProcessBuilder pb,
-			@Nullable char[] password) throws IOException {
-		// Start the subprocess
-		out.println("starting " + pb.command() + " in directory "
-				+ pb.directory() + " with environment " + pb.environment());
-		subprocess = pb.start();
-		if (subprocess == null)
-			throw new IOException("unknown failure creating process");
-		start = new Date();
-		accounting.runStarted();
-
-		// Capture its stdout and stderr
-		new AsyncCopy(subprocess.getInputStream(), stdout, pid);
-		new AsyncCopy(subprocess.getErrorStream(), stderr);
-		if (password != null)
-			new PasswordWriterThread(subprocess, password);
-	}
-
-	/**
-	 * Assemble the process builder. Does not launch the subprocess.
-	 * 
-	 * @param local
-	 *            The local worker container.
-	 * @param executeWorkflowCommand
-	 *            The reference to the workflow engine implementation.
-	 * @param workflow
-	 *            The workflow to execute.
-	 * @param workingDir
-	 *            The working directory to use.
-	 * @param inputBaclava
-	 *            What file to read a baclava document from (or <tt>null</tt>)
-	 * @param inputFiles
-	 *            The mapping from inputs to files.
-	 * @param inputValues
-	 *            The mapping from inputs to literal values.
-	 * @param outputBaclava
-	 *            What file to write a baclava document to (or <tt>null</tt>)
-	 * @param securityDir
-	 *            The credential manager directory.
-	 * @param password
-	 *            The password for the credential manager.
-	 * @param environment
-	 *            The seed environment
-	 * @param token
-	 *            The run identifier that the server wants to use.
-	 * @param runtime
-	 *            Any runtime parameters to Java.
-	 * @return The configured process builder.
-	 * @throws IOException
-	 *             If file handling fails
-	 * @throws UnsupportedEncodingException
-	 *             If we can't encode any text (unlikely)
-	 * @throws FileNotFoundException
-	 *             If we can't write the workflow out (unlikely)
-	 */
-	@Nonnull
-	ProcessBuilder createProcessBuilder(@Nonnull LocalWorker local,
-			@Nonnull String executeWorkflowCommand, @Nonnull byte[] workflow,
-			@Nonnull File workingDir, @Nullable File inputBaclava,
-			@Nonnull Map<String, File> inputFiles,
-			@Nonnull Map<String, String> inputValues,
-			@Nonnull Map<String, String> inputDelimiters,
-			@Nullable File outputBaclava, @Nonnull File securityDir,
-			@Nonnull char[] password, boolean generateProvenance,
-			@Nonnull Map<String, String> environment, @Nonnull String token,
-			@Nonnull List<String> runtime) throws IOException,
-			UnsupportedEncodingException, FileNotFoundException {
-		ProcessBuilder pb = new ProcessBuilder();
-		pb.command().add(TIME);
-		/*
-		 * WARNING! HERE THERE BE DRAGONS! BE CAREFUL HERE!
-		 * 
-		 * Work around _Maven_ bug with permissions in zip files! The executable
-		 * bit is stripped by Maven's handling of file permissions, and there's
-		 * no practical way to work around it without massively increasing the
-		 * pain in other ways. Only want this on Unix - Windows isn't affected
-		 * by this - so we use the file separator as a proxy for whether this is
-		 * a true POSIX system. Ugly! Ugly ugly ugly...
-		 * 
-		 * http://jira.codehaus.org/browse/MASSEMBLY-337 is relevant, but not
-		 * the whole story as we don't want to use a non-standard packaging
-		 * method as there's a real chance of it going wrong in an unexpected
-		 * way then. Other parts of the story are that the executable bit isn't
-		 * preserved when unpacking with the dependency plugin, and there's no
-		 * way to be sure that the servlet container will preserve the bit
-		 * either (as that's probably using a Java-based ZIP engine).
-		 */
-		if (File.separatorChar == '/')
-			pb.command().add("/bin/sh");
-		pb.command().add(executeWorkflowCommand);
-		if (runtime != null)
-			pb.command().addAll(runtime);
-
-		// Enable verbose logging
-		pb.command().add("-logfile");
-		pb.command().add(
-				new File(new File(workingDir, "logs"), "detail.log")
-						.getAbsolutePath());
-
-		if (securityDir != null) {
-			pb.command().add(CREDENTIAL_MANAGER_DIRECTORY);
-			pb.command().add(securityDir.getAbsolutePath());
-			out.println("security dir location: " + securityDir);
-		}
-		if (password != null) {
-			pb.command().add(CREDENTIAL_MANAGER_PASSWORD);
-			out.println("password of length " + password.length
-					+ " will be written to subprocess stdin");
-		}
-
-		// Add arguments denoting inputs
-		if (inputBaclava != null) {
-			pb.command().add("-inputdoc");
-			pb.command().add(inputBaclava.getAbsolutePath());
-			if (!inputBaclava.exists())
-				throw new IOException("input baclava file doesn't exist");
-		} else {
-			for (Entry<String, File> port : inputFiles.entrySet()) {
-				if (port.getValue() == null)
-					continue;
-				pb.command().add("-inputfile");
-				pb.command().add(port.getKey());
-				pb.command().add(port.getValue().getAbsolutePath());
-				if (!port.getValue().exists())
-					throw new IOException("input file for port \"" + port
-							+ "\" doesn't exist");
-			}
-			for (Entry<String, String> port : inputValues.entrySet()) {
-				if (port.getValue() == null)
-					continue;
-				pb.command().add("-inputfile");
-				pb.command().add(port.getKey());
-				File f = createTempFile(".tav_in_", null, workingDir);
-				pb.command().add(f.getAbsolutePath());
-				write(f, port.getValue(), "UTF-8");
-			}
-			for (Entry<String, String> delim : inputDelimiters.entrySet()) {
-				if (delim.getValue() == null)
-					continue;
-				pb.command().add("-inputdelimiter");
-				pb.command().add(delim.getKey());
-				pb.command().add(delim.getValue());
-			}
-		}
-
-		// Add arguments denoting outputs
-		if (outputBaclava != null) {
-			pb.command().add("-outputdoc");
-			pb.command().add(outputBaclava.getAbsolutePath());
-			if (!outputBaclava.getParentFile().exists())
-				throw new IOException(
-						"parent directory of output baclava file does not exist");
-			if (outputBaclava.exists())
-				throw new IOException("output baclava file exists");
-			// Provenance cannot be supported when using baclava output
-		} else {
-			File out = new File(workingDir, "out");
-			if (!out.mkdir())
-				throw new IOException("failed to make output directory \"out\"");
-			// Taverna needs the dir to *not* exist now
-			forceDelete(out);
-			pb.command().add("-outputdir");
-			pb.command().add(out.getAbsolutePath());
-			// Enable provenance generation
-			if (generateProvenance) {
-				pb.command().add("-embedded");
-				pb.command().add("-provenance");
-				pb.command().add("-provbundle");
-				pb.command().add("out.bundle.zip");
-			}
-		}
-
-		// Add an argument holding the workflow
-		File tmp = createTempFile(".wf_", ".scufl2", workingDir);
-		try (OutputStream os = new FileOutputStream(tmp)) {
-			os.write(workflow);
-		}
-		pb.command().add(workflowFile.getAbsolutePath());
-
-		// Indicate what working directory to use
-		pb.directory(workingDir);
-		wd = workingDir;
-
-		Map<String, String> env = pb.environment();
-		for (String name : ENVIRONMENT_TO_REMOVE)
-			env.remove(name);
-
-		// Merge any options we have had imposed on us from outside
-		env.putAll(environment);
-
-		// Patch the environment to deal with TAVUTILS-17
-		assert env.get("PATH") != null;
-		env.put("PATH", new File(System.getProperty("java.home"), "bin")
-				+ pathSeparator + env.get("PATH"));
-		// Patch the environment to deal with TAVSERV-189
-		env.put("TAVERNA_APPHOME", workingDir.getCanonicalPath());
-		// Patch the environment to deal with TAVSERV-224
-		env.put("TAVERNA_RUN_ID", token);
-		if (interactionHost != null || local.interactionFeedURL != null
-				|| local.webdavURL != null) {
-			env.put("INTERACTION_HOST", makeInterHost(local.interactionFeedURL));
-			env.put("INTERACTION_PORT", makeInterPort(local.interactionFeedURL));
-			env.put("INTERACTION_FEED", makeInterPath(local.interactionFeedURL));
-			env.put("INTERACTION_WEBDAV",
-					local.webdavURL != null ? local.webdavURL.getPath()
-							: interactionWebdavPath);
-			String pub = makeInterPublish(local.publishURL);
-			if (pub != null && !pub.isEmpty())
-				env.put("INTERACTION_PUBLISH", pub);
-		}
-		return pb;
-	}
-
-	@Nullable
-	private static String makeInterHost(@Nullable URL url) {
-		if (url == null)
-			return interactionHost;
-		return url.getProtocol() + "://" + url.getHost();
-	}
-
-	@Nullable
-	private static String makeInterPort(@Nullable URL url) {
-		if (url == null)
-			return interactionPort;
-		int port = url.getPort();
-		if (port == -1)
-			port = url.getDefaultPort();
-		return Integer.toString(port);
-	}
-
-	@Nullable
-	private static String makeInterPublish(@Nullable URL url)
-			throws IOException {
-		if (url == null)
-			return null;
-		try {
-			URI uri = url.toURI();
-			int port = uri.getPort();
-			if (port == -1)
-				return uri.getScheme() + "://" + uri.getHost();
-			else
-				return uri.getScheme() + "://" + uri.getHost() + ":" + port;
-		} catch (URISyntaxException e) {
-			throw new IOException("problem constructing publication url", e);
-		}
-	}
-
-	@Nullable
-	private static String makeInterPath(@Nullable URL url) {
-		if (url == null)
-			return interactionFeedPath;
-		return url.getPath();
-	}
-
-	/**
-	 * Kills off the subprocess if it exists and is alive.
-	 */
-	@Override
-	public void killWorker() {
-		if (!finished && subprocess != null) {
-			final Holder<Integer> code = new Holder<>();
-			for (TimingOutTask tot : new TimingOutTask[] { new TimingOutTask() {
-				/** Check if the workflow terminated of its own accord */
-				@Override
-				public void doIt() throws IOException {
-					code.value = subprocess.exitValue();
-					accounting.runCeased();
-					buildUR(code.value == 0 ? Completed : Failed, code.value);
-				}
-			}, new TimingOutTask() {
-				/** Tell the workflow to stop */
-				@Override
-				public void doIt() throws IOException {
-					code.value = killNicely();
-					accounting.runCeased();
-					buildUR(code.value == 0 ? Completed : Aborted, code.value);
-				}
-			}, new TimingOutTask() {
-				/** Kill the workflow, kill it with fire */
-				@Override
-				public void doIt() throws IOException {
-					code.value = killHard();
-					accounting.runCeased();
-					buildUR(code.value == 0 ? Completed : Aborted, code.value);
-				}
-			} }) {
-				try {
-					tot.doOrTimeOut(DEATH_TIME);
-				} catch (Exception e) {
-				}
-				if (code.value != null)
-					break;
-			}
-			finished = true;
-			setExitCode(code.value);
-			readyToSendEmail = true;
-		}
-	}
-
-	/**
-	 * Integrated spot to handle writing/logging of the exit code.
-	 * 
-	 * @param code
-	 *            The exit code.
-	 */
-	private void setExitCode(int code) {
-		exitCode = code;
-		if (code > 256 - 8) {
-			out.println("workflow aborted, Raven issue = " + (code - 256));
-		} else if (code > 128) {
-			out.println("workflow aborted, signal=" + (code - 128));
-		} else {
-			out.println("workflow exited, code=" + code);
-		}
-	}
-
-	@Nonnull
-	private JobUsageRecord newUR() throws DatatypeConfigurationException {
-		try {
-			if (wd != null)
-				return new JobUsageRecord(wd.getName());
-		} catch (RuntimeException e) {
-		}
-		return new JobUsageRecord("unknown");
-	}
-
-	/**
-	 * Fills in the accounting information from the exit code and stderr.
-	 * 
-	 * @param exitCode
-	 *            The exit code from the program.
-	 */
-	private void buildUR(@Nonnull Status status, int exitCode) {
-		try {
-			Date now = new Date();
-			long user = -1, sys = -1, real = -1;
-			Matcher m = TimeRE.matcher(stderr.toString());
-			ur = newUR();
-			while (m.find())
-				for (int i = 1; i < 6; i += 2)
-					if (m.group(i + 1).equals("user"))
-						user = parseDuration(m.group(i));
-					else if (m.group(i + 1).equals("sys")
-							|| m.group(i + 1).equals("system"))
-						sys = parseDuration(m.group(i));
-					else if (m.group(i + 1).equals("real")
-							|| m.group(i + 1).equals("elapsed"))
-						real = parseDuration(m.group(i));
-			if (user != -1)
-				ur.addCpuDuration(user).setUsageType("user");
-			if (sys != -1)
-				ur.addCpuDuration(sys).setUsageType("system");
-			ur.addUser(System.getProperty("user.name"), null);
-			ur.addStartAndEnd(start, now);
-			if (real != -1)
-				ur.addWallDuration(real);
-			else
-				ur.addWallDuration(now.getTime() - start.getTime());
-			ur.setStatus(status.toString());
-			ur.addHost(getLocalHost().getHostName());
-			ur.addResource("exitcode", Integer.toString(exitCode));
-			ur.addDisk(sizeOfDirectory(wd)).setStorageUnit("B");
-			if (urreceiver != null)
-				urreceiver.acceptUsageRecord(ur.marshal());
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-	}
-
-	private long parseDuration(@Nonnull String durationString) {
-		try {
-			return (long) (parseDouble(durationString) * 1000);
-		} catch (NumberFormatException nfe) {
-			// Not a double; maybe MM:SS.mm or HH:MM:SS.mm
-		}
-		long dur = 0;
-		for (String d : durationString.split(":"))
-			try {
-				dur = 60 * dur + parseLong(d);
-			} catch (NumberFormatException nfe) {
-				// Assume that only one thing is fractional, and that it is last
-				return 60000 * dur + (long) (parseDouble(d) * 1000);
-			}
-		return dur * 1000;
-	}
-
-	private void signal(@Nonnull String signal) throws Exception {
-		int pid = getPID();
-		if (pid > 0
-				&& getRuntime().exec("kill -" + signal + " " + pid).waitFor() == 0)
-			return;
-		throw new Exception("failed to send signal " + signal + " to process "
-				+ pid);
-	}
-
-	@Nullable
-	private Integer killNicely() {
-		try {
-			signal("TERM");
-			return subprocess.waitFor();
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	@Nullable
-	private Integer killHard() {
-		try {
-			signal("QUIT");
-			return subprocess.waitFor();
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	/**
-	 * Move the worker out of the stopped state and back to operating.
-	 * 
-	 * @throws Exception
-	 *             if it fails.
-	 */
-	@Override
-	public void startWorker() throws Exception {
-		signal("CONT");
-		stopped = false;
-	}
-
-	/**
-	 * Move the worker into the stopped state from the operating state.
-	 * 
-	 * @throws Exception
-	 *             if it fails.
-	 */
-	@Override
-	public void stopWorker() throws Exception {
-		signal("STOP");
-		stopped = true;
-	}
-
-	/**
-	 * @return The status of the workflow run. Note that this can be an
-	 *         expensive operation.
-	 */
-	@Override
-	public RemoteStatus getWorkerStatus() {
-		if (subprocess == null)
-			return Initialized;
-		if (finished)
-			return Finished;
-		try {
-			setExitCode(subprocess.exitValue());
-		} catch (IllegalThreadStateException e) {
-			if (stopped)
-				return Stopped;
-			return Operating;
-		}
-		finished = true;
-		readyToSendEmail = true;
-		accounting.runCeased();
-		buildUR(exitCode.intValue() == 0 ? Completed : Failed, exitCode);
-		return Finished;
-	}
-
-	@Override
-	public String getConfiguration() {
-		return "";
-	}
-
-	@Override
-	public String getName() {
-		return DEFAULT_LISTENER_NAME;
-	}
-
-	@Override
-	public String getProperty(String propName) throws RemoteException {
-		switch (Property.is(propName)) {
-		case STDOUT:
-			return stdout.toString();
-		case STDERR:
-			return stderr.toString();
-		case EXIT_CODE:
-			return (exitCode == null) ? "" : exitCode.toString();
-		case EMAIL:
-			return emailAddress;
-		case READY_TO_NOTIFY:
-			return Boolean.toString(readyToSendEmail);
-		case USAGE:
-			try {
-				JobUsageRecord toReturn;
-				if (subprocess == null) {
-					toReturn = newUR();
-					toReturn.setStatus(Held.toString());
-				} else if (ur == null) {
-					toReturn = newUR();
-					toReturn.setStatus(Started.toString());
-					toReturn.addStartAndEnd(start, new Date());
-					toReturn.addUser(System.getProperty("user.name"), null);
-				} else {
-					toReturn = ur;
-				}
-				/*
-				 * Note that this record is not to be pushed to the server. That
-				 * is done elsewhere (when a proper record is produced)
-				 */
-				return toReturn.marshal();
-			} catch (Exception e) {
-				e.printStackTrace();
-				return "";
-			}
-		default:
-			throw new RemoteException("unknown property");
-		}
-	}
-
-	@Override
-	public String getType() {
-		return DEFAULT_LISTENER_NAME;
-	}
-
-	@Override
-	public String[] listProperties() {
-		return Property.names();
-	}
-
-	@Override
-	public void setProperty(String propName, String value)
-			throws RemoteException {
-		switch (Property.is(propName)) {
-		case EMAIL:
-			emailAddress = value;
-			return;
-		case READY_TO_NOTIFY:
-			readyToSendEmail = parseBoolean(value);
-			return;
-		case STDOUT:
-		case STDERR:
-		case EXIT_CODE:
-		case USAGE:
-			throw new RemoteException("property is read only");
-		default:
-			throw new RemoteException("unknown property");
-		}
-	}
-
-	@Override
-	public RemoteListener getDefaultListener() {
-		return this;
-	}
-
-	@Override
-	public void setURReceiver(@Nonnull UsageRecordReceiver receiver) {
-		urreceiver = receiver;
-	}
-
-	@Override
-	public void deleteLocalResources() throws ImplementationException {
-		try {
-			if (workflowFile != null && workflowFile.getParentFile().exists())
-				forceDelete(workflowFile);
-		} catch (IOException e) {
-			throw new ImplementationException("problem deleting workflow file",
-					e);
-		}
-	}
-}
-
-/**
- * An engine for asynchronously copying from an {@link InputStream} to a
- * {@link Writer}.
- * 
- * @author Donal Fellows
- */
-class AsyncCopy extends Thread {
-	@Nonnull
-	private BufferedReader from;
-	@Nonnull
-	private Writer to;
-	@Nullable
-	private Holder<Integer> pidHolder;
-
-	AsyncCopy(@Nonnull InputStream from, @Nonnull Writer to)
-			throws UnsupportedEncodingException {
-		this(from, to, null);
-	}
-
-	AsyncCopy(@Nonnull InputStream from, @Nonnull Writer to,
-			@Nullable Holder<Integer> pid) throws UnsupportedEncodingException {
-		this.from = new BufferedReader(new InputStreamReader(from,
-				SYSTEM_ENCODING));
-		this.to = to;
-		this.pidHolder = pid;
-		setDaemon(true);
-		start();
-	}
-
-	@Override
-	public void run() {
-		try {
-			if (pidHolder != null) {
-				String line = from.readLine();
-				if (line.matches("^pid:\\d+$"))
-					synchronized (pidHolder) {
-						pidHolder.value = parseInt(line.substring(4));
-					}
-				else
-					to.write(line + System.getProperty("line.separator"));
-			}
-			copy(from, to);
-		} catch (IOException e) {
-		}
-	}
-}
-
-/**
- * A helper for asynchronously writing a password to a subprocess's stdin.
- * 
- * @author Donal Fellows
- */
-class PasswordWriterThread extends Thread {
-	private OutputStream to;
-	private char[] chars;
-
-	PasswordWriterThread(@Nonnull Process to, @Nonnull char[] chars) {
-		this.to = to.getOutputStream();
-		assert chars != null;
-		this.chars = chars;
-		setDaemon(true);
-		start();
-	}
-
-	@Override
-	public void run() {
-		try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(to,
-				SYSTEM_ENCODING))) {
-			pw.println(chars);
-		} catch (UnsupportedEncodingException e) {
-			// Not much we can do here
-			e.printStackTrace();
-		} finally {
-			/*
-			 * We don't trust GC to clear password from memory. We also take
-			 * care not to clear the default password!
-			 */
-			if (chars != KEYSTORE_PASSWORD)
-				Arrays.fill(chars, '\00');
-		}
-	}
-}
-
-enum Property {
-	STDOUT("stdout"), STDERR("stderr"), EXIT_CODE("exitcode"), READY_TO_NOTIFY(
-			"readyToNotify"), EMAIL("notificationAddress"), USAGE("usageRecord");
-
-	private String s;
-
-	private Property(String s) {
-		this.s = s;
-		pmap.put(s, this);
-	}
-
-	@Override
-	public String toString() {
-		return s;
-	}
-
-	public static Property is(@Nonnull String s) {
-		return pmap.get(s);
-	}
-
-	@Nonnull
-	public static String[] names() {
-		return pmap.keySet().toArray(new String[pmap.size()]);
-	}
-}
-
-enum Status {
-	Aborted, Completed, Failed, Held, Queued, Started, Suspended
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java
deleted file mode 100644
index fa2e117..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.impl.utils;
-/*
- * 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.
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Utility class that handles filename validation on different target platforms.
- * 
- * @author Donal Fellows.
- */
-public abstract class FilenameVerifier {
-	private FilenameVerifier(){}
-
-	static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
-
-	@SuppressWarnings("serial")
-	private static final Set<String> ILLEGAL_NAMES = new HashSet<String>(){{
-		add("");
-		add("..");
-		add(".");
-		if (IS_WINDOWS) {
-			add("con");
-			add("prn");
-			add("nul");
-			add("aux");
-			for (int i = 1; i <= 9; i++) {
-				add("com" + i);
-				add("lpt" + i);
-			}
-		}
-	}};
-	@SuppressWarnings("serial")
-	private static final Set<Character> ILLEGAL_CHARS = new HashSet<Character>(){{
-		add('/');
-		for (char i=0 ; i<32 ; i++)
-			add(i);
-		if (IS_WINDOWS) {
-			add('\\');
-			add('>');
-			add('<');
-			add(':');
-			add('"');
-			add('|');
-			add('?');
-			add('*');
-		} else {
-			add(' '); // whitespace; too much trouble from these
-			add('\t');
-			add('\r');
-			add('\n');
-		}
-	}};
-	@SuppressWarnings("serial")
-	private static final Set<String> ILLEGAL_PREFIXES = new HashSet<String>(){{
-		if (IS_WINDOWS) {
-			add("con.");
-			add("prn.");
-			add("nul.");
-			add("aux.");
-			for (int i = 1; i <= 9; i++) {
-				add("com" + i + ".");
-				add("lpt" + i + ".");
-			}
-		}
-	}};
-	@SuppressWarnings("serial")
-	private static final Set<String> ILLEGAL_SUFFIXES = new HashSet<String>(){{
-		if (IS_WINDOWS) {
-			add(" ");
-			add(".");
-		}
-	}};
-
-	/**
-	 * Construct a file handle, applying platform-specific filename validation
-	 * rules in the process.
-	 * 
-	 * @param dir
-	 *            The directory acting as a root, which is assumed to be
-	 *            correctly named. May be <tt>null</tt>.
-	 * @param names
-	 *            The names of filename fragments to apply the checks to. Must
-	 *            have at least one value.
-	 * @return The file handle. Never <tt>null</tt>.
-	 * @throws IOException
-	 *             If validation fails.
-	 */
-	public static File getValidatedFile(File dir, String... names)
-			throws IOException {
-		if (names.length == 0)
-			throw new IOException("empty filename");
-		File f = dir;
-		for (String name : names) {
-			String low = name.toLowerCase();
-			if (ILLEGAL_NAMES.contains(low))
-				throw new IOException("illegal filename");
-			for (char c : ILLEGAL_CHARS)
-				if (low.indexOf(c) >= 0)
-					throw new IOException("illegal filename");
-			for (String s : ILLEGAL_PREFIXES)
-				if (low.startsWith(s))
-					throw new IOException("illegal filename");
-			for (String s : ILLEGAL_SUFFIXES)
-				if (low.endsWith(s))
-					throw new IOException("illegal filename");
-			f = new File(f, name);
-		}
-		assert f != null;
-		return f;
-	}
-
-	/**
-	 * Create a file handle where the underlying file must exist.
-	 * 
-	 * @param dir
-	 *            The directory that will contain the file.
-	 * @param name
-	 *            The name of the file; will be validated.
-	 * @return The handle.
-	 * @throws IOException
-	 *             If validation fails or the file doesn't exist.
-	 */
-	public static File getValidatedExistingFile(File dir, String name)
-			throws IOException {
-		File f = getValidatedFile(dir, name);
-		if (!f.exists())
-			throw new IOException("doesn't exist");
-		return f;
-	}
-
-	/**
-	 * Create a file handle where the underlying file must <i>not</i> exist.
-	 * 
-	 * @param dir
-	 *            The directory that will contain the file.
-	 * @param name
-	 *            The name of the file; will be validated.
-	 * @return The handle. The file will not be created by this method.
-	 * @throws IOException
-	 *             If validation fails or the file does exist.
-	 */
-	public static File getValidatedNewFile(File dir, String name)
-			throws IOException {
-		File f = getValidatedFile(dir, name);
-		if (f.exists())
-			throw new IOException("already exists");
-		return f;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java
deleted file mode 100644
index c5b1b7b..0000000
--- a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.taverna.server.localworker.impl.utils;
-/*
- * 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.
- */
-
-import javax.annotation.Nullable;
-
-/**
- * A class that handles running a task that can take some time.
- * 
- * @author Donal Fellows
- * 
- */
-public abstract class TimingOutTask extends Thread {
-	public abstract void doIt() throws Exception;
-
-	@Nullable
-	private Exception ioe;
-
-	@Override
-	public final void run() {
-		try {
-			doIt();
-		} catch (Exception ioe) {
-			this.ioe = ioe;
-		}
-	}
-
-	public TimingOutTask() {
-		this.setDaemon(true);
-	}
-
-	public void doOrTimeOut(long timeout) throws Exception {
-		start();
-		try {
-			join(timeout);
-		} catch (InterruptedException e) {
-			interrupt();
-		}
-		if (ioe != null)
-			throw ioe;
-	}
-}
\ No newline at end of file


[36/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
package org.taverna -> org.apache.taverna


Project: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/commit/00397eff
Tree: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/tree/00397eff
Diff: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/diff/00397eff

Branch: refs/heads/master
Commit: 00397eff0a8170b29906c56c06d5c624bd5fbbe2
Parents: 63fdb89
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Tue Jan 9 23:22:30 2018 +0000
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Tue Jan 9 23:22:30 2018 +0000

----------------------------------------------------------------------
 .../server/port_description/AbsentValue.java    |   26 +
 .../server/port_description/AbstractPort.java   |   39 +
 .../AbstractPortDescription.java                |   42 +
 .../server/port_description/AbstractValue.java  |   45 +
 .../server/port_description/ErrorValue.java     |   38 +
 .../port_description/InputDescription.java      |   64 +
 .../server/port_description/LeafValue.java      |   32 +
 .../server/port_description/ListValue.java      |   45 +
 .../server/port_description/Namespaces.java     |   25 +
 .../port_description/OutputDescription.java     |   65 +
 .../server/port_description/package-info.java   |   32 +
 .../port_description/utils/IntAdapter.java      |   45 +
 .../server/port_description/AbsentValue.java    |   26 -
 .../server/port_description/AbstractPort.java   |   39 -
 .../AbstractPortDescription.java                |   42 -
 .../server/port_description/AbstractValue.java  |   45 -
 .../server/port_description/ErrorValue.java     |   38 -
 .../port_description/InputDescription.java      |   64 -
 .../server/port_description/LeafValue.java      |   32 -
 .../server/port_description/ListValue.java      |   45 -
 .../server/port_description/Namespaces.java     |   25 -
 .../port_description/OutputDescription.java     |   65 -
 .../server/port_description/package-info.java   |   32 -
 .../port_description/utils/IntAdapter.java      |   45 -
 .../server/port_description/JaxbSanityTest.java |  114 ++
 .../server/port_description/JaxbSanityTest.java |  114 --
 .../taverna/server/rmidaemon/Registry.java      |   88 +
 .../taverna/server/rmidaemon/package-info.java  |   21 +
 .../org/taverna/server/rmidaemon/Registry.java  |   88 -
 .../taverna/server/rmidaemon/package-info.java  |   21 -
 .../remote/IllegalStateTransitionException.java |   49 +
 .../remote/ImplementationException.java         |   39 +
 .../localworker/remote/RemoteDirectory.java     |   75 +
 .../remote/RemoteDirectoryEntry.java            |   75 +
 .../server/localworker/remote/RemoteFile.java   |  111 ++
 .../server/localworker/remote/RemoteInput.java  |  105 ++
 .../localworker/remote/RemoteListener.java      |   90 +
 .../localworker/remote/RemoteRunFactory.java    |   97 ++
 .../remote/RemoteSecurityContext.java           |   47 +
 .../localworker/remote/RemoteSingleRun.java     |  267 +++
 .../server/localworker/remote/RemoteStatus.java |   53 +
 .../remote/StillWorkingOnItException.java       |   33 +
 .../server/localworker/remote/package-info.java |   22 +
 .../localworker/server/UsageRecordReceiver.java |   42 +
 .../server/localworker/server/package-info.java |   22 +
 .../remote/IllegalStateTransitionException.java |   49 -
 .../remote/ImplementationException.java         |   39 -
 .../localworker/remote/RemoteDirectory.java     |   75 -
 .../remote/RemoteDirectoryEntry.java            |   75 -
 .../server/localworker/remote/RemoteFile.java   |  111 --
 .../server/localworker/remote/RemoteInput.java  |  105 --
 .../localworker/remote/RemoteListener.java      |   90 -
 .../localworker/remote/RemoteRunFactory.java    |   97 --
 .../remote/RemoteSecurityContext.java           |   47 -
 .../localworker/remote/RemoteSingleRun.java     |  267 ---
 .../server/localworker/remote/RemoteStatus.java |   53 -
 .../remote/StillWorkingOnItException.java       |   33 -
 .../server/localworker/remote/package-info.java |   22 -
 .../localworker/server/UsageRecordReceiver.java |   42 -
 .../server/localworker/server/package-info.java |   22 -
 .../taverna/server/unixforker/Forker.java       |  221 +++
 .../org/taverna/server/unixforker/Forker.java   |  221 ---
 .../master/ContentsDescriptorBuilder.java       |  305 ++++
 .../taverna/server/master/DirectoryREST.java    |  388 +++++
 .../server/master/FileConcatenation.java        |   84 +
 .../apache/taverna/server/master/InputREST.java |  265 +++
 .../taverna/server/master/InteractionFeed.java  |  120 ++
 .../server/master/ListenerPropertyREST.java     |   91 +
 .../taverna/server/master/ListenersREST.java    |  106 ++
 .../taverna/server/master/ManagementState.java  |  228 +++
 .../apache/taverna/server/master/RunREST.java   |  512 ++++++
 .../taverna/server/master/RunSecurityREST.java  |  316 ++++
 .../server/master/SingleListenerREST.java       |  110 ++
 .../taverna/server/master/TavernaServer.java    | 1438 ++++++++++++++++
 .../server/master/TavernaServerSupport.java     |  970 +++++++++++
 .../taverna/server/master/admin/Admin.java      | 1113 +++++++++++++
 .../taverna/server/master/admin/AdminBean.java  |  807 +++++++++
 .../server/master/admin/package-info.java       |   46 +
 .../taverna/server/master/api/ContentTypes.java |   63 +
 .../server/master/api/DirectoryBean.java        |   32 +
 .../taverna/server/master/api/FeedBean.java     |   29 +
 .../taverna/server/master/api/InputBean.java    |   37 +
 .../server/master/api/ListenerPropertyBean.java |   31 +
 .../server/master/api/ListenersBean.java        |   29 +
 .../server/master/api/ManagementModel.java      |   74 +
 .../server/master/api/OneListenerBean.java      |   30 +
 .../taverna/server/master/api/RunBean.java      |   33 +
 .../taverna/server/master/api/SecurityBean.java |   30 +
 .../taverna/server/master/api/SupportAware.java |   37 +
 .../server/master/api/TavernaServerBean.java    |  114 ++
 .../taverna/server/master/api/package-info.java |   22 +
 .../server/master/common/Capability.java        |   38 +
 .../server/master/common/Credential.java        |  162 ++
 .../server/master/common/DirEntryReference.java |  106 ++
 .../server/master/common/InputDescription.java  |  123 ++
 .../server/master/common/Namespaces.java        |   52 +
 .../server/master/common/Permission.java        |   56 +
 .../server/master/common/ProfileList.java       |   55 +
 .../taverna/server/master/common/Roles.java     |   38 +
 .../server/master/common/RunReference.java      |   80 +
 .../taverna/server/master/common/Status.java    |   57 +
 .../taverna/server/master/common/Trust.java     |   92 +
 .../taverna/server/master/common/Uri.java       |  445 +++++
 .../server/master/common/VersionedElement.java  |   78 +
 .../taverna/server/master/common/Workflow.java  |  380 +++++
 .../server/master/common/package-info.java      |   42 +
 .../server/master/common/version/Version.java   |   56 +
 .../taverna/server/master/defaults/Default.java |  112 ++
 .../server/master/defaults/package-info.java    |   21 +
 .../exceptions/BadInputPortNameException.java   |   34 +
 .../exceptions/BadPropertyValueException.java   |   39 +
 .../exceptions/BadStateChangeException.java     |   48 +
 .../exceptions/FilesystemAccessException.java   |   51 +
 .../exceptions/GeneralFailureException.java     |   41 +
 .../exceptions/InvalidCredentialException.java  |   49 +
 .../master/exceptions/NoCreateException.java    |   45 +
 .../exceptions/NoCredentialException.java       |   31 +
 .../master/exceptions/NoDestroyException.java   |   37 +
 .../exceptions/NoDirectoryEntryException.java   |   37 +
 .../master/exceptions/NoListenerException.java  |   46 +
 .../master/exceptions/NoUpdateException.java    |   46 +
 .../master/exceptions/NotOwnerException.java    |   36 +
 .../master/exceptions/OverloadedException.java  |   48 +
 .../master/exceptions/UnknownRunException.java  |   40 +
 .../server/master/exceptions/package-info.java  |   42 +
 .../taverna/server/master/facade/Facade.java    |   86 +
 .../server/master/facade/package-info.java      |   23 +
 .../factories/ConfigurableRunFactory.java       |  146 ++
 .../master/factories/ListenerFactory.java       |   59 +
 .../server/master/factories/RunFactory.java     |   53 +
 .../server/master/factories/package-info.java   |   23 +
 .../identity/AuthorityDerivedIDMapper.java      |   63 +
 .../master/identity/CompositeIDMapper.java      |   78 +
 .../master/identity/ConstantIDMapper.java       |   45 +
 .../server/master/identity/NameIDMapper.java    |   63 +
 .../identity/StrippedDownAuthProvider.java      |  294 ++++
 .../taverna/server/master/identity/User.java    |  166 ++
 .../server/master/identity/UserStore.java       |  402 +++++
 .../server/master/identity/UserStoreAPI.java    |  107 ++
 .../identity/WorkflowInternalAuthProvider.java  |  317 ++++
 .../server/master/identity/package-info.java    |   23 +
 .../interaction/InteractionFeedSupport.java     |  329 ++++
 .../server/master/interaction/package-info.java |   23 +
 .../server/master/interfaces/Directory.java     |   95 ++
 .../master/interfaces/DirectoryEntry.java       |   60 +
 .../taverna/server/master/interfaces/File.java  |   82 +
 .../taverna/server/master/interfaces/Input.java |  105 ++
 .../server/master/interfaces/Listener.java      |   77 +
 .../master/interfaces/LocalIdentityMapper.java  |   42 +
 .../master/interfaces/MessageDispatcher.java    |   58 +
 .../server/master/interfaces/Policy.java        |  133 ++
 .../server/master/interfaces/RunStore.java      |   95 ++
 .../interfaces/SecurityContextFactory.java      |   45 +
 .../server/master/interfaces/TavernaRun.java    |  232 +++
 .../interfaces/TavernaSecurityContext.java      |  226 +++
 .../master/interfaces/UriBuilderFactory.java    |   56 +
 .../server/master/interfaces/package-info.java  |   23 +
 .../localworker/AbstractRemoteRunFactory.java   |  452 +++++
 .../master/localworker/ForkRunFactory.java      |  336 ++++
 .../localworker/IdAwareForkRunFactory.java      |  529 ++++++
 .../master/localworker/LocalWorkerFactory.java  |   44 +
 .../master/localworker/LocalWorkerState.java    |  475 ++++++
 .../master/localworker/PersistedState.java      |  270 +++
 .../server/master/localworker/StreamLogger.java |   78 +
 .../server/master/localworker/package-info.java |   23 +
 .../master/notification/EmailDispatcher.java    |  126 ++
 .../master/notification/JabberDispatcher.java   |  153 ++
 .../master/notification/NotificationEngine.java |  158 ++
 .../notification/RateLimitedDispatcher.java     |  102 ++
 .../master/notification/SMSDispatcher.java      |  171 ++
 .../master/notification/TwitterDispatcher.java  |  145 ++
 .../master/notification/atom/AtomFeed.java      |  147 ++
 .../server/master/notification/atom/Event.java  |  123 ++
 .../master/notification/atom/EventDAO.java      |  230 +++
 .../master/notification/atom/package-info.java  |   42 +
 .../master/notification/package-info.java       |   23 +
 .../taverna/server/master/package-info.java     |   24 +
 .../server/master/rest/ContentTypes.java        |   41 +
 .../server/master/rest/DirectoryContents.java   |   74 +
 .../taverna/server/master/rest/FileSegment.java |   91 +
 .../server/master/rest/InteractionFeedREST.java |  139 ++
 .../server/master/rest/ListenerDefinition.java  |   45 +
 .../master/rest/MakeOrUpdateDirEntry.java       |   69 +
 .../master/rest/TavernaServerDirectoryREST.java |  253 +++
 .../master/rest/TavernaServerInputREST.java     |  368 ++++
 .../master/rest/TavernaServerListenersREST.java |  441 +++++
 .../server/master/rest/TavernaServerREST.java   |  617 +++++++
 .../master/rest/TavernaServerRunREST.java       |  810 +++++++++
 .../master/rest/TavernaServerSecurityREST.java  |  788 +++++++++
 .../rest/handler/AccessDeniedHandler.java       |   34 +
 .../rest/handler/BadInputPortNameHandler.java   |   36 +
 .../rest/handler/BadPropertyValueHandler.java   |   36 +
 .../rest/handler/BadStateChangeHandler.java     |   36 +
 .../master/rest/handler/EntryHandler.java       |  147 ++
 .../server/master/rest/handler/FeedHandler.java |   82 +
 .../rest/handler/FileConcatenationHandler.java  |   77 +
 .../master/rest/handler/FileMessageHandler.java |   93 ++
 .../master/rest/handler/FileSegmentHandler.java |   87 +
 .../rest/handler/FilesystemAccessHandler.java   |   36 +
 .../rest/handler/GeneralFailureHandler.java     |   34 +
 .../server/master/rest/handler/HandlerCore.java |   84 +
 .../rest/handler/IllegalArgumentHandler.java    |   34 +
 .../handler/ImplementationProblemHandler.java   |   34 +
 .../rest/handler/InputStreamMessageHandler.java |  120 ++
 .../rest/handler/InvalidCredentialHandler.java  |   36 +
 .../rest/handler/JAXBExceptionHandler.java      |   35 +
 .../rest/handler/NegotiationFailedHandler.java  |   38 +
 .../master/rest/handler/NoCreateHandler.java    |   36 +
 .../rest/handler/NoCredentialHandler.java       |   34 +
 .../master/rest/handler/NoDestroyHandler.java   |   36 +
 .../rest/handler/NoDirectoryEntryHandler.java   |   36 +
 .../master/rest/handler/NoListenerHandler.java  |   36 +
 .../master/rest/handler/NoUpdateHandler.java    |   36 +
 .../master/rest/handler/NotOwnerHandler.java    |   34 +
 .../master/rest/handler/OverloadedHandler.java  |   35 +
 .../master/rest/handler/PermissionHandler.java  |   87 +
 .../rest/handler/Scufl2DocumentHandler.java     |  100 ++
 .../rest/handler/T2FlowDocumentHandler.java     |  131 ++
 .../master/rest/handler/URIListHandler.java     |  134 ++
 .../master/rest/handler/UnknownRunHandler.java  |   36 +
 .../master/rest/handler/ZipStreamHandler.java   |   67 +
 .../master/rest/handler/package-info.java       |   44 +
 .../server/master/rest/package-info.java        |   44 +
 .../taverna/server/master/soap/DirEntry.java    |  113 ++
 .../server/master/soap/FileContents.java        |  184 ++
 .../server/master/soap/PermissionList.java      |   63 +
 .../server/master/soap/TavernaServerSOAP.java   | 1566 ++++++++++++++++++
 .../server/master/soap/WrappedWorkflow.java     |  169 ++
 .../server/master/soap/ZippedDirectory.java     |  102 ++
 .../server/master/soap/package-info.java        |   44 +
 .../server/master/usage/UsageRecord.java        |  130 ++
 .../master/usage/UsageRecordRecorder.java       |  178 ++
 .../server/master/usage/package-info.java       |   22 +
 .../server/master/utils/CallTimeLogger.java     |  100 ++
 .../server/master/utils/CallTimingFilter.java   |   81 +
 .../server/master/utils/CapabilityLister.java   |   60 +
 .../master/utils/CertificateChainFetcher.java   |  212 +++
 .../server/master/utils/Contextualizer.java     |   79 +
 .../taverna/server/master/utils/DerbyUtils.java |   84 +
 .../server/master/utils/FilenameUtils.java      |  281 ++++
 .../utils/FlushThreadLocalCacheInterceptor.java |   34 +
 .../server/master/utils/InvocationCounter.java  |   61 +
 .../taverna/server/master/utils/JCECheck.java   |   73 +
 .../taverna/server/master/utils/JDOSupport.java |  285 ++++
 .../master/utils/LoggingDerbyAdapter.java       |  154 ++
 .../server/master/utils/OneShotThread.java      |   26 +
 .../taverna/server/master/utils/RestUtils.java  |   45 +
 .../master/utils/RuntimeExceptionWrapper.java   |   50 +
 .../server/master/utils/UsernamePrincipal.java  |   82 +
 .../utils/WSDLHeadOptionsInterceptor.java       |   81 +
 .../master/utils/WebappAwareDataSource.java     |  147 ++
 .../taverna/server/master/utils/X500Utils.java  |  120 ++
 .../server/master/utils/package-info.java       |   23 +
 .../master/worker/CompletionNotifier.java       |   58 +
 .../server/master/worker/FactoryBean.java       |   39 +
 .../server/master/worker/PasswordIssuer.java    |   73 +
 .../server/master/worker/PolicyImpl.java        |  171 ++
 .../server/master/worker/PolicyLimits.java      |   56 +
 .../server/master/worker/RemoteRunDelegate.java |  980 +++++++++++
 .../server/master/worker/RunConnection.java     |  252 +++
 .../server/master/worker/RunDBSupport.java      |   96 ++
 .../server/master/worker/RunDatabase.java       |  324 ++++
 .../server/master/worker/RunDatabaseDAO.java    |  323 ++++
 .../master/worker/RunFactoryConfiguration.java  |  411 +++++
 .../master/worker/SecurityContextDelegate.java  |  662 ++++++++
 .../worker/SecurityContextDelegateImpl.java     |  311 ++++
 .../master/worker/SecurityContextFactory.java   |  167 ++
 .../SimpleFormattedCompletionNotifier.java      |   77 +
 .../worker/VelocityCompletionNotifier.java      |  121 ++
 .../server/master/worker/WorkerModel.java       |  216 +++
 .../server/master/worker/package-info.java      |   23 +
 .../master/ContentsDescriptorBuilder.java       |  305 ----
 .../taverna/server/master/DirectoryREST.java    |  388 -----
 .../server/master/FileConcatenation.java        |   84 -
 .../org/taverna/server/master/InputREST.java    |  265 ---
 .../taverna/server/master/InteractionFeed.java  |  120 --
 .../server/master/ListenerPropertyREST.java     |   91 -
 .../taverna/server/master/ListenersREST.java    |  106 --
 .../taverna/server/master/ManagementState.java  |  228 ---
 .../java/org/taverna/server/master/RunREST.java |  512 ------
 .../taverna/server/master/RunSecurityREST.java  |  316 ----
 .../server/master/SingleListenerREST.java       |  110 --
 .../taverna/server/master/TavernaServer.java    | 1438 ----------------
 .../server/master/TavernaServerSupport.java     |  970 -----------
 .../org/taverna/server/master/admin/Admin.java  | 1113 -------------
 .../taverna/server/master/admin/AdminBean.java  |  807 ---------
 .../server/master/admin/package-info.java       |   46 -
 .../taverna/server/master/api/ContentTypes.java |   63 -
 .../server/master/api/DirectoryBean.java        |   32 -
 .../org/taverna/server/master/api/FeedBean.java |   29 -
 .../taverna/server/master/api/InputBean.java    |   37 -
 .../server/master/api/ListenerPropertyBean.java |   31 -
 .../server/master/api/ListenersBean.java        |   29 -
 .../server/master/api/ManagementModel.java      |   74 -
 .../server/master/api/OneListenerBean.java      |   30 -
 .../org/taverna/server/master/api/RunBean.java  |   33 -
 .../taverna/server/master/api/SecurityBean.java |   30 -
 .../taverna/server/master/api/SupportAware.java |   37 -
 .../server/master/api/TavernaServerBean.java    |  114 --
 .../taverna/server/master/api/package-info.java |   22 -
 .../server/master/common/Capability.java        |   38 -
 .../server/master/common/Credential.java        |  162 --
 .../server/master/common/DirEntryReference.java |  106 --
 .../server/master/common/InputDescription.java  |  123 --
 .../server/master/common/Namespaces.java        |   52 -
 .../server/master/common/Permission.java        |   56 -
 .../server/master/common/ProfileList.java       |   55 -
 .../org/taverna/server/master/common/Roles.java |   38 -
 .../server/master/common/RunReference.java      |   80 -
 .../taverna/server/master/common/Status.java    |   57 -
 .../org/taverna/server/master/common/Trust.java |   92 -
 .../org/taverna/server/master/common/Uri.java   |  445 -----
 .../server/master/common/VersionedElement.java  |   78 -
 .../taverna/server/master/common/Workflow.java  |  380 -----
 .../server/master/common/package-info.java      |   42 -
 .../server/master/common/version/Version.java   |   56 -
 .../taverna/server/master/defaults/Default.java |  112 --
 .../server/master/defaults/package-info.java    |   21 -
 .../exceptions/BadInputPortNameException.java   |   34 -
 .../exceptions/BadPropertyValueException.java   |   39 -
 .../exceptions/BadStateChangeException.java     |   48 -
 .../exceptions/FilesystemAccessException.java   |   51 -
 .../exceptions/GeneralFailureException.java     |   41 -
 .../exceptions/InvalidCredentialException.java  |   49 -
 .../master/exceptions/NoCreateException.java    |   45 -
 .../exceptions/NoCredentialException.java       |   31 -
 .../master/exceptions/NoDestroyException.java   |   37 -
 .../exceptions/NoDirectoryEntryException.java   |   37 -
 .../master/exceptions/NoListenerException.java  |   46 -
 .../master/exceptions/NoUpdateException.java    |   46 -
 .../master/exceptions/NotOwnerException.java    |   36 -
 .../master/exceptions/OverloadedException.java  |   48 -
 .../master/exceptions/UnknownRunException.java  |   40 -
 .../server/master/exceptions/package-info.java  |   42 -
 .../taverna/server/master/facade/Facade.java    |   86 -
 .../server/master/facade/package-info.java      |   23 -
 .../factories/ConfigurableRunFactory.java       |  146 --
 .../master/factories/ListenerFactory.java       |   59 -
 .../server/master/factories/RunFactory.java     |   53 -
 .../server/master/factories/package-info.java   |   23 -
 .../identity/AuthorityDerivedIDMapper.java      |   63 -
 .../master/identity/CompositeIDMapper.java      |   78 -
 .../master/identity/ConstantIDMapper.java       |   45 -
 .../server/master/identity/NameIDMapper.java    |   63 -
 .../identity/StrippedDownAuthProvider.java      |  294 ----
 .../taverna/server/master/identity/User.java    |  166 --
 .../server/master/identity/UserStore.java       |  402 -----
 .../server/master/identity/UserStoreAPI.java    |  107 --
 .../identity/WorkflowInternalAuthProvider.java  |  317 ----
 .../server/master/identity/package-info.java    |   23 -
 .../interaction/InteractionFeedSupport.java     |  329 ----
 .../server/master/interaction/package-info.java |   23 -
 .../server/master/interfaces/Directory.java     |   95 --
 .../master/interfaces/DirectoryEntry.java       |   60 -
 .../taverna/server/master/interfaces/File.java  |   82 -
 .../taverna/server/master/interfaces/Input.java |  105 --
 .../server/master/interfaces/Listener.java      |   77 -
 .../master/interfaces/LocalIdentityMapper.java  |   42 -
 .../master/interfaces/MessageDispatcher.java    |   58 -
 .../server/master/interfaces/Policy.java        |  133 --
 .../server/master/interfaces/RunStore.java      |   95 --
 .../interfaces/SecurityContextFactory.java      |   45 -
 .../server/master/interfaces/TavernaRun.java    |  232 ---
 .../interfaces/TavernaSecurityContext.java      |  226 ---
 .../master/interfaces/UriBuilderFactory.java    |   56 -
 .../server/master/interfaces/package-info.java  |   23 -
 .../localworker/AbstractRemoteRunFactory.java   |  452 -----
 .../master/localworker/ForkRunFactory.java      |  336 ----
 .../localworker/IdAwareForkRunFactory.java      |  529 ------
 .../master/localworker/LocalWorkerFactory.java  |   44 -
 .../master/localworker/LocalWorkerState.java    |  475 ------
 .../master/localworker/PersistedState.java      |  270 ---
 .../server/master/localworker/StreamLogger.java |   78 -
 .../server/master/localworker/package-info.java |   23 -
 .../master/notification/EmailDispatcher.java    |  126 --
 .../master/notification/JabberDispatcher.java   |  153 --
 .../master/notification/NotificationEngine.java |  158 --
 .../notification/RateLimitedDispatcher.java     |  102 --
 .../master/notification/SMSDispatcher.java      |  171 --
 .../master/notification/TwitterDispatcher.java  |  145 --
 .../master/notification/atom/AtomFeed.java      |  147 --
 .../server/master/notification/atom/Event.java  |  123 --
 .../master/notification/atom/EventDAO.java      |  230 ---
 .../master/notification/atom/package-info.java  |   42 -
 .../master/notification/package-info.java       |   23 -
 .../org/taverna/server/master/package-info.java |   24 -
 .../server/master/rest/ContentTypes.java        |   41 -
 .../server/master/rest/DirectoryContents.java   |   74 -
 .../taverna/server/master/rest/FileSegment.java |   91 -
 .../server/master/rest/InteractionFeedREST.java |  139 --
 .../server/master/rest/ListenerDefinition.java  |   45 -
 .../master/rest/MakeOrUpdateDirEntry.java       |   69 -
 .../master/rest/TavernaServerDirectoryREST.java |  253 ---
 .../master/rest/TavernaServerInputREST.java     |  368 ----
 .../master/rest/TavernaServerListenersREST.java |  441 -----
 .../server/master/rest/TavernaServerREST.java   |  617 -------
 .../master/rest/TavernaServerRunREST.java       |  810 ---------
 .../master/rest/TavernaServerSecurityREST.java  |  788 ---------
 .../rest/handler/AccessDeniedHandler.java       |   34 -
 .../rest/handler/BadInputPortNameHandler.java   |   36 -
 .../rest/handler/BadPropertyValueHandler.java   |   36 -
 .../rest/handler/BadStateChangeHandler.java     |   36 -
 .../master/rest/handler/EntryHandler.java       |  147 --
 .../server/master/rest/handler/FeedHandler.java |   82 -
 .../rest/handler/FileConcatenationHandler.java  |   77 -
 .../master/rest/handler/FileMessageHandler.java |   93 --
 .../master/rest/handler/FileSegmentHandler.java |   87 -
 .../rest/handler/FilesystemAccessHandler.java   |   36 -
 .../rest/handler/GeneralFailureHandler.java     |   34 -
 .../server/master/rest/handler/HandlerCore.java |   84 -
 .../rest/handler/IllegalArgumentHandler.java    |   34 -
 .../handler/ImplementationProblemHandler.java   |   34 -
 .../rest/handler/InputStreamMessageHandler.java |  120 --
 .../rest/handler/InvalidCredentialHandler.java  |   36 -
 .../rest/handler/JAXBExceptionHandler.java      |   35 -
 .../rest/handler/NegotiationFailedHandler.java  |   38 -
 .../master/rest/handler/NoCreateHandler.java    |   36 -
 .../rest/handler/NoCredentialHandler.java       |   34 -
 .../master/rest/handler/NoDestroyHandler.java   |   36 -
 .../rest/handler/NoDirectoryEntryHandler.java   |   36 -
 .../master/rest/handler/NoListenerHandler.java  |   36 -
 .../master/rest/handler/NoUpdateHandler.java    |   36 -
 .../master/rest/handler/NotOwnerHandler.java    |   34 -
 .../master/rest/handler/OverloadedHandler.java  |   35 -
 .../master/rest/handler/PermissionHandler.java  |   87 -
 .../rest/handler/Scufl2DocumentHandler.java     |  100 --
 .../rest/handler/T2FlowDocumentHandler.java     |  131 --
 .../master/rest/handler/URIListHandler.java     |  134 --
 .../master/rest/handler/UnknownRunHandler.java  |   36 -
 .../master/rest/handler/ZipStreamHandler.java   |   67 -
 .../master/rest/handler/package-info.java       |   44 -
 .../server/master/rest/package-info.java        |   44 -
 .../taverna/server/master/soap/DirEntry.java    |  113 --
 .../server/master/soap/FileContents.java        |  184 --
 .../server/master/soap/PermissionList.java      |   63 -
 .../server/master/soap/TavernaServerSOAP.java   | 1566 ------------------
 .../server/master/soap/WrappedWorkflow.java     |  169 --
 .../server/master/soap/ZippedDirectory.java     |  102 --
 .../server/master/soap/package-info.java        |   44 -
 .../server/master/usage/UsageRecord.java        |  130 --
 .../master/usage/UsageRecordRecorder.java       |  178 --
 .../server/master/usage/package-info.java       |   22 -
 .../server/master/utils/CallTimeLogger.java     |  100 --
 .../server/master/utils/CallTimingFilter.java   |   81 -
 .../server/master/utils/CapabilityLister.java   |   60 -
 .../master/utils/CertificateChainFetcher.java   |  212 ---
 .../server/master/utils/Contextualizer.java     |   79 -
 .../taverna/server/master/utils/DerbyUtils.java |   84 -
 .../server/master/utils/FilenameUtils.java      |  281 ----
 .../utils/FlushThreadLocalCacheInterceptor.java |   34 -
 .../server/master/utils/InvocationCounter.java  |   61 -
 .../taverna/server/master/utils/JCECheck.java   |   73 -
 .../taverna/server/master/utils/JDOSupport.java |  285 ----
 .../master/utils/LoggingDerbyAdapter.java       |  154 --
 .../server/master/utils/OneShotThread.java      |   26 -
 .../taverna/server/master/utils/RestUtils.java  |   45 -
 .../master/utils/RuntimeExceptionWrapper.java   |   50 -
 .../server/master/utils/UsernamePrincipal.java  |   82 -
 .../utils/WSDLHeadOptionsInterceptor.java       |   81 -
 .../master/utils/WebappAwareDataSource.java     |  147 --
 .../taverna/server/master/utils/X500Utils.java  |  120 --
 .../server/master/utils/package-info.java       |   23 -
 .../master/worker/CompletionNotifier.java       |   58 -
 .../server/master/worker/FactoryBean.java       |   39 -
 .../server/master/worker/PasswordIssuer.java    |   73 -
 .../server/master/worker/PolicyImpl.java        |  171 --
 .../server/master/worker/PolicyLimits.java      |   56 -
 .../server/master/worker/RemoteRunDelegate.java |  980 -----------
 .../server/master/worker/RunConnection.java     |  252 ---
 .../server/master/worker/RunDBSupport.java      |   96 --
 .../server/master/worker/RunDatabase.java       |  324 ----
 .../server/master/worker/RunDatabaseDAO.java    |  323 ----
 .../master/worker/RunFactoryConfiguration.java  |  411 -----
 .../master/worker/SecurityContextDelegate.java  |  662 --------
 .../worker/SecurityContextDelegateImpl.java     |  311 ----
 .../master/worker/SecurityContextFactory.java   |  167 --
 .../SimpleFormattedCompletionNotifier.java      |   77 -
 .../worker/VelocityCompletionNotifier.java      |  121 --
 .../server/master/worker/WorkerModel.java       |  216 ---
 .../server/master/worker/package-info.java      |   23 -
 .../taverna/server/master/JaxbSanityTest.java   |  370 +++++
 .../server/master/TavernaServerImplTest.java    |  262 +++
 .../master/WorkflowSerializationTest.java       |   84 +
 .../taverna/server/master/mocks/ExampleRun.java |  465 ++++++
 .../taverna/server/master/mocks/MockPolicy.java |   75 +
 .../master/mocks/SimpleListenerFactory.java     |   80 +
 .../mocks/SimpleNonpersistentRunStore.java      |  167 ++
 .../server/master/mocks/SimpleServerPolicy.java |  126 ++
 .../taverna/server/master/JaxbSanityTest.java   |  370 -----
 .../server/master/TavernaServerImplTest.java    |  262 ---
 .../master/WorkflowSerializationTest.java       |   84 -
 .../taverna/server/master/mocks/ExampleRun.java |  465 ------
 .../taverna/server/master/mocks/MockPolicy.java |   75 -
 .../master/mocks/SimpleListenerFactory.java     |   80 -
 .../mocks/SimpleNonpersistentRunStore.java      |  167 --
 .../server/master/mocks/SimpleServerPolicy.java |  126 --
 .../server/localworker/api/Constants.java       |  154 ++
 .../server/localworker/api/RunAccounting.java   |   35 +
 .../taverna/server/localworker/api/Worker.java  |  148 ++
 .../server/localworker/api/WorkerFactory.java   |   34 +
 .../localworker/impl/DirectoryDelegate.java     |  174 ++
 .../server/localworker/impl/FileDelegate.java   |  155 ++
 .../server/localworker/impl/LocalWorker.java    |  782 +++++++++
 .../localworker/impl/TavernaRunManager.java     |  255 +++
 .../server/localworker/impl/WorkerCore.java     |  931 +++++++++++
 .../impl/utils/FilenameVerifier.java            |  169 ++
 .../localworker/impl/utils/TimingOutTask.java   |   56 +
 .../server/localworker/api/Constants.java       |  154 --
 .../server/localworker/api/RunAccounting.java   |   35 -
 .../taverna/server/localworker/api/Worker.java  |  148 --
 .../server/localworker/api/WorkerFactory.java   |   34 -
 .../localworker/impl/DirectoryDelegate.java     |  174 --
 .../server/localworker/impl/FileDelegate.java   |  155 --
 .../server/localworker/impl/LocalWorker.java    |  782 ---------
 .../localworker/impl/TavernaRunManager.java     |  255 ---
 .../server/localworker/impl/WorkerCore.java     |  931 -----------
 .../impl/utils/FilenameVerifier.java            |  169 --
 .../localworker/impl/utils/TimingOutTask.java   |   56 -
 .../localworker/impl/LocalWorkerTest.java       |  564 +++++++
 .../localworker/impl/LocalWorkerTest.java       |  564 -------
 520 files changed, 39308 insertions(+), 39308 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbsentValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbsentValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbsentValue.java
new file mode 100644
index 0000000..140d6a5
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbsentValue.java
@@ -0,0 +1,26 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPort.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPort.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPort.java
new file mode 100644
index 0000000..5ed8d70
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPort.java
@@ -0,0 +1,39 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPortDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPortDescription.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPortDescription.java
new file mode 100644
index 0000000..721e8c8
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPortDescription.java
@@ -0,0 +1,42 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractValue.java
new file mode 100644
index 0000000..1ded5c7
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractValue.java
@@ -0,0 +1,45 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ErrorValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ErrorValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ErrorValue.java
new file mode 100644
index 0000000..641c380
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ErrorValue.java
@@ -0,0 +1,38 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/InputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/InputDescription.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/InputDescription.java
new file mode 100644
index 0000000..c11baa1
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/InputDescription.java
@@ -0,0 +1,64 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/LeafValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/LeafValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/LeafValue.java
new file mode 100644
index 0000000..95658bc
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/LeafValue.java
@@ -0,0 +1,32 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ListValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ListValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ListValue.java
new file mode 100644
index 0000000..f3e8ff1
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ListValue.java
@@ -0,0 +1,45 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/Namespaces.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/Namespaces.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/Namespaces.java
new file mode 100644
index 0000000..f60e6c4
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/Namespaces.java
@@ -0,0 +1,25 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/OutputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/OutputDescription.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/OutputDescription.java
new file mode 100644
index 0000000..2f402d1
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/OutputDescription.java
@@ -0,0 +1,65 @@
+/*
+ */
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/package-info.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/package-info.java
new file mode 100644
index 0000000..76228db
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/package-info.java
@@ -0,0 +1,32 @@
+/*
+ */
+@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;
+/*
+ * 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.
+ */
+
+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/00397eff/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/utils/IntAdapter.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/utils/IntAdapter.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/utils/IntAdapter.java
new file mode 100644
index 0000000..de9a3a8
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/utils/IntAdapter.java
@@ -0,0 +1,45 @@
+/*
+ */
+package org.taverna.server.port_description.utils;
+/*
+ * 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.
+ */
+
+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/00397eff/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
deleted file mode 100644
index 140d6a5..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 5ed8d70..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 721e8c8..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 1ded5c7..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 641c380..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index c11baa1..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 95658bc..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index f3e8ff1..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index f60e6c4..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 2f402d1..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- */
-package org.taverna.server.port_description;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 76228db..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- */
-@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;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index de9a3a8..0000000
--- a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- */
-package org.taverna.server.port_description.utils;
-/*
- * 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.
- */
-
-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/00397eff/taverna-server-port-description/src/test/java/org/apache/taverna/server/port_description/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/test/java/org/apache/taverna/server/port_description/JaxbSanityTest.java b/taverna-server-port-description/src/test/java/org/apache/taverna/server/port_description/JaxbSanityTest.java
new file mode 100644
index 0000000..de15cfa
--- /dev/null
+++ b/taverna-server-port-description/src/test/java/org/apache/taverna/server/port_description/JaxbSanityTest.java
@@ -0,0 +1,114 @@
+package org.taverna.server.port_description;
+/*
+ * 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.
+ */
+
+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());
+	}
+}



[22/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecordRecorder.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecordRecorder.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecordRecorder.java
new file mode 100644
index 0000000..18aeb3b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/UsageRecordRecorder.java
@@ -0,0 +1,178 @@
+/*
+ */
+package org.taverna.server.master.usage;
+/*
+ * 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.
+ */
+
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PreDestroy;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.logging.Log;
+import org.apache.taverna.server.usagerecord.JobUsageRecord;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.ManagementModel;
+import org.taverna.server.master.utils.Contextualizer;
+import org.taverna.server.master.utils.JDOSupport;
+
+/**
+ * A simple state-aware writer of usage records. It just appends them, one by
+ * one, to the file whose name is stored in the state.
+ * 
+ * @author Donal Fellows
+ */
+public class UsageRecordRecorder extends JDOSupport<UsageRecord> {
+	private Log log = getLog("Taverna.Server.Webapp");
+	public UsageRecordRecorder() {
+		super(UsageRecord.class);
+	}
+
+	private String logFile = null;
+	private boolean disableDB = false;
+	private ManagementModel state;
+	private Contextualizer contextualizer;
+	private String logDestination;
+	private PrintWriter writer;
+	private Object lock = new Object();
+	private UsageRecordRecorder self;
+
+	/**
+	 * @param state
+	 *            the state to set
+	 */
+	@Required
+	public void setState(ManagementModel state) {
+		this.state = state;
+	}
+
+	@Required
+	public void setSelf(UsageRecordRecorder self) {
+		this.self = self;
+	}
+
+	public void setLogFile(String logFile) {
+		this.logFile = (logFile == null || logFile.equals("none")) ? null : logFile;
+	}
+
+	public void setDisableDB(String disable) {
+		disableDB = "yes".equalsIgnoreCase(disable);
+	}
+
+	/**
+	 * @param contextualizer
+	 *            the system's contextualizer, used to allow making the UR dump
+	 *            file be placed relative to the webapp.
+	 */
+	@Required
+	public void setContextualizer(Contextualizer contextualizer) {
+		this.contextualizer = contextualizer;
+	}
+
+	/**
+	 * Accept a usage record for recording.
+	 * 
+	 * @param usageRecord
+	 *            The serialized usage record to record.
+	 */
+	public void storeUsageRecord(String usageRecord) {
+		String logfile = state.getUsageRecordLogFile();
+		if (logfile == null)
+			logfile = this.logFile;
+		if (logfile != null) {
+			logfile = contextualizer.contextualize(logfile);
+			synchronized (lock) {
+				if (!logfile.equals(logDestination)) {
+					if (writer != null) {
+						writer.close();
+						writer = null;
+					}
+					try {
+						writer = new PrintWriter(new FileWriter(logfile));
+						logDestination = logfile;
+					} catch (IOException e) {
+						log.warn("failed to open usage record log file", e);
+					}
+				}
+				if (writer != null) {
+					writer.println(usageRecord);
+					writer.flush();
+				}
+			}
+		}
+
+		if (!disableDB)
+			saveURtoDB(usageRecord);
+	}
+
+	/**
+	 * How to save a usage record to the database.
+	 * 
+	 * @param usageRecord
+	 *            The serialized usage record to save.
+	 */
+	protected void saveURtoDB(String usageRecord) {
+		UsageRecord ur;
+		try {
+			ur = new UsageRecord(usageRecord);
+		} catch (JAXBException e) {
+			log.warn("failed to deserialize usage record", e);
+			return;
+		}
+
+		try {
+			self.saveURtoDB(ur);
+		} catch (RuntimeException e) {
+			log.warn("failed to save UR to database", e);
+		}
+	}
+
+	@WithinSingleTransaction
+	public void saveURtoDB(UsageRecord ur) {
+		persist(ur);
+	}
+
+	@WithinSingleTransaction
+	public List<JobUsageRecord> getUsageRecords() {
+		List<String> urs = allByDate();
+		List<JobUsageRecord> result = new ArrayList<>();
+		for (String ur : urs)
+			try {
+				result.add(JobUsageRecord.unmarshal(ur));
+			} catch (JAXBException e) {
+				log.warn("failed to unmarshal UR", e);
+			}
+		return result;
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> allByDate() {
+		return (List<String>) namedQuery("allByDate").execute();
+	}
+
+	@PreDestroy
+	public void close() {
+		if (writer != null)
+			writer.close();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/package-info.java
new file mode 100644
index 0000000..a7fe733
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/usage/package-info.java
@@ -0,0 +1,22 @@
+/*
+ */
+/**
+ * Resource usage recording mechanism.
+ */
+package org.taverna.server.master.usage;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimeLogger.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimeLogger.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimeLogger.java
new file mode 100644
index 0000000..4452935
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimeLogger.java
@@ -0,0 +1,100 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static java.lang.String.format;
+import static java.lang.System.nanoTime;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.apache.commons.logging.Log;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.master.common.version.Version;
+
+/**
+ * This class is responsible for timing all invocations of publicly-exposed
+ * methods of the webapp. It's connected to the webapp through an AspectJ-style
+ * pointcut that targets a custom annotation.
+ * 
+ * @author Donal Fellows
+ */
+@Aspect
+@ManagedResource(objectName = JMX_ROOT + "PerformanceMonitor", description = "The performance monitor for Taverna Server "
+		+ Version.JAVA
+		+ ". Writes to application log using the category 'Taverna.Server.Performance'.")
+public class CallTimeLogger {
+	private long threshold = 4000000;
+	private Log log = getLog("Taverna.Server.Performance");
+
+	@ManagedAttribute(description = "Threshold beneath which monitored call times are not logged. In nanoseconds.")
+	public long getThreshold() {
+		return threshold;
+	}
+
+	@ManagedAttribute(description = "Threshold beneath which monitored call times are not logged. In nanoseconds.")
+	public void setThreshold(long threshold) {
+		this.threshold = threshold;
+	}
+
+	/**
+	 * The timer for this aspect. The wrapped invocation will be timed, and a
+	 * log message written if the configured threshold is exceeded.
+	 * 
+	 * @param call
+	 *            The call being wrapped.
+	 * @return The result of the call.
+	 * @throws Throwable
+	 *             If anything goes wrong with the wrapped call.
+	 * @see System#nanoTime()
+	 */
+	@Around("@annotation(org.taverna.server.master.utils.CallTimeLogger.PerfLogged)")
+	public Object time(ProceedingJoinPoint call) throws Throwable {
+		long fore = nanoTime();
+		try {
+			return call.proceed();
+		} finally {
+			long aft = nanoTime();
+			long elapsed = aft - fore;
+			if (elapsed > threshold)
+				log.info(format("call to %s took %.3fms", call.toShortString(),
+						elapsed / 1000000.0));
+		}
+	}
+
+	/**
+	 * Mark methods that should be counted by the invocation counter.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@Retention(RUNTIME)
+	@Documented
+	@Target(METHOD)
+	public static @interface PerfLogged {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimingFilter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimingFilter.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimingFilter.java
new file mode 100644
index 0000000..d8ad78d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CallTimingFilter.java
@@ -0,0 +1,81 @@
+/**
+ * 
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static java.lang.String.format;
+import static java.lang.System.nanoTime;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Logs the time it takes to service HTTP calls into Taverna Server.
+ * <p>
+ * This class is currently not used.
+ * 
+ * @author Donal Fellows
+ */
+public class CallTimingFilter implements Filter {
+	private Log log;
+	private String name;
+
+	@Override
+	public void init(FilterConfig filterConfig) throws ServletException {
+		log = getLog("Taverna.Server.Performance");
+		name = filterConfig.getInitParameter("name");
+	}
+
+	@Override
+	public void doFilter(ServletRequest request, ServletResponse response,
+			FilterChain chain) throws IOException, ServletException {
+		if (request instanceof HttpServletRequest)
+			doFilter((HttpServletRequest) request,
+					(HttpServletResponse) response, chain);
+		else
+			chain.doFilter(request, response);
+	}
+
+	public void doFilter(HttpServletRequest request,
+			HttpServletResponse response, FilterChain chain)
+			throws IOException, ServletException {
+		long start = nanoTime();
+		chain.doFilter(request, response);
+		long elapsedTime = nanoTime() - start;
+		log.info(format("%s call to %s %s took %.3fms", name,
+				request.getMethod(), request.getRequestURI(),
+				elapsedTime / 1000000.0));
+	}
+
+	@Override
+	public void destroy() {
+		log = null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CapabilityLister.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CapabilityLister.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CapabilityLister.java
new file mode 100644
index 0000000..1387e05
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CapabilityLister.java
@@ -0,0 +1,60 @@
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import javax.annotation.PostConstruct;
+
+import org.taverna.server.master.common.Capability;
+
+/**
+ * Utility for listing the capabilities supported by this Taverna Server
+ * installation.
+ * 
+ * @author Donal Fellows
+ */
+public class CapabilityLister {
+	public static final String CAPABILITY_RESOURCE_FILE = "/capabilities.properties";
+	private Properties properties = new Properties();
+
+	@PostConstruct
+	void loadCapabilities() throws IOException {
+		try (InputStream is = getClass().getResourceAsStream(
+				CAPABILITY_RESOURCE_FILE)) {
+			if (is != null)
+				properties.load(is);
+		}
+	}
+
+	public List<Capability> getCapabilities() {
+		List<Capability> caps = new ArrayList<>();
+		for (Entry<Object, Object> entry : properties.entrySet()) {
+			Capability c = new Capability();
+			c.capability = URI.create(entry.getKey().toString());
+			c.version = entry.getValue().toString();
+			caps.add(c);
+		}
+		return caps;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CertificateChainFetcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CertificateChainFetcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CertificateChainFetcher.java
new file mode 100644
index 0000000..76ef017
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/CertificateChainFetcher.java
@@ -0,0 +1,212 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.unmodifiableList;
+
+import java.io.IOException;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import javax.xml.ws.Holder;
+
+/**
+ * Obtains the certificate chain for an arbitrary SSL service. Maintains a
+ * cache.
+ * 
+ * @author Donal Fellows
+ */
+public class CertificateChainFetcher {
+	public String getProtocol() {
+		return protocol;
+	}
+
+	public void setProtocol(String protocol) {
+		this.protocol = protocol;
+	}
+
+	public String getKeystoreType() {
+		return keystoreType;
+	}
+
+	public void setKeystoreType(String keystoreType) {
+		this.keystoreType = keystoreType;
+	}
+
+	public String getAlgorithm() {
+		return algorithm;
+	}
+
+	public void setAlgorithm(String algorithm) {
+		this.algorithm = algorithm;
+	}
+
+	public int getTimeout() {
+		return timeout;
+	}
+
+	public void setTimeout(int timeout) {
+		this.timeout = timeout;
+	}
+
+	public void setSecure(boolean secure) {
+		this.secure = secure;
+	}
+
+	private boolean secure = true;
+	private String protocol = "TLS";
+	private String keystoreType = KeyStore.getDefaultType();
+	private String algorithm = TrustManagerFactory.getDefaultAlgorithm();
+	private int timeout = 10000;
+
+	/**
+	 * Get the certificate chain for a service.
+	 * 
+	 * @param host
+	 *            The host (name or IP address) to contact the service on.
+	 * @param port
+	 *            The port to contact the service on.
+	 * @return The certificate chain, or <tt>null</tt> if no credentials are
+	 *         available.
+	 * @throws NoSuchAlgorithmException
+	 *             If the trust manager cannot be set up because of algorithm
+	 *             problems.
+	 * @throws KeyStoreException
+	 *             If the trust manager cannot be set up because of problems
+	 *             with the keystore type.
+	 * @throws CertificateException
+	 *             If a bad certificate is present in the default keystore;
+	 *             <i>should be impossible</i>.
+	 * @throws IOException
+	 *             If problems happen when trying to contact the service.
+	 * @throws KeyManagementException
+	 *             If the SSL context can't have its special context manager
+	 *             installed.
+	 */
+	private X509Certificate[] getCertificateChainForService(String host,
+			int port) throws NoSuchAlgorithmException, KeyStoreException,
+			CertificateException, IOException, KeyManagementException {
+		KeyStore ks = KeyStore.getInstance(keystoreType);
+		SSLContext context = SSLContext.getInstance(protocol);
+		TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+		ks.load(null, null);
+		tmf.init(ks);
+		final Holder<X509Certificate[]> chain = new Holder<>();
+		final X509TrustManager defaultTrustManager = (X509TrustManager) tmf
+				.getTrustManagers()[0];
+		context.init(null, new TrustManager[] { new X509TrustManager() {
+			@Override
+			public void checkClientTrusted(X509Certificate[] clientChain,
+					String authType) throws CertificateException {
+				throw new UnsupportedOperationException();
+			}
+
+			@Override
+			public void checkServerTrusted(X509Certificate[] serverChain,
+					String authType) throws CertificateException {
+				chain.value = serverChain;
+				defaultTrustManager.checkServerTrusted(serverChain, authType);
+			}
+
+			@Override
+			public X509Certificate[] getAcceptedIssuers() {
+				throw new UnsupportedOperationException();
+			}
+		} }, null);
+		SSLSocketFactory factory = context.getSocketFactory();
+		try (SSLSocket socket = (SSLSocket) factory.createSocket(host, port)) {
+			socket.setSoTimeout(timeout);
+			socket.startHandshake();
+		} catch (SSLException e) {
+			// Ignore
+		}
+		return chain.value;
+	}
+
+	private Map<URI, List<X509Certificate>> cache = new HashMap<>();
+
+	/**
+	 * Gets the certificate chain for a service identified by URI.
+	 * 
+	 * @param uri
+	 *            The URI of the (secure) service to identify.
+	 * @return The certificate chain. Will be <tt>null</tt> if the service is
+	 *         not secure.
+	 * @throws IOException
+	 *             If the service is unreachable or other connection problems
+	 *             occur.
+	 * @throws GeneralSecurityException
+	 *             If any of a number of security-related problems occur, such
+	 *             as an inability to match detailed security protocols.
+	 */
+	public List<X509Certificate> getTrustsForURI(URI uri) throws IOException,
+			GeneralSecurityException {
+		if (!secure)
+			return null;
+		synchronized (this) {
+			if (!cache.containsKey(uri)) {
+				int port = uri.getPort();
+				if (port == -1)
+					switch (uri.getScheme()) {
+					case "http":
+						port = 80;
+						break;
+					case "https":
+						port = 443;
+						break;
+					default:
+						return null;
+					}
+				X509Certificate[] chain = getCertificateChainForService(
+						uri.getHost(), port);
+				if (chain != null)
+					cache.put(uri, unmodifiableList(asList(chain)));
+				else
+					cache.put(uri, null);
+			}
+			return cache.get(uri);
+		}
+	}
+
+	/**
+	 * Flushes the cache.
+	 */
+	public void flushCache() {
+		synchronized (this) {
+			cache.clear();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/Contextualizer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/Contextualizer.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/Contextualizer.java
new file mode 100644
index 0000000..e0ee4d1
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/Contextualizer.java
@@ -0,0 +1,79 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.UriInfo;
+
+import org.springframework.web.context.ServletContextAware;
+import org.taverna.server.master.common.version.Version;
+
+/**
+ * Convert a string (URL, etc) to a version that is contextualized to the
+ * web-application.
+ * 
+ * @author Donal Fellows
+ */
+public class Contextualizer implements ServletContextAware {
+	static final String ROOT_PLACEHOLDER = "%{WEBAPPROOT}";
+	static final String VERSION_PLACEHOLDER = "%{VERSION}";
+	static final String BASE_PLACEHOLDER = "%{BASEURL}";
+
+	/**
+	 * Apply the contextualization operation. This consists of replacing the
+	 * string <tt>{@value #ROOT_PLACEHOLDER}</tt> with the real root of the webapp.
+	 * 
+	 * @param input
+	 *            the string to contextualize
+	 * @return the contextualized string
+	 */
+	public String contextualize(String input) {
+		// Hack to work around bizarre CXF bug
+		String path = context.getRealPath("/").replace("%2D", "-");
+		return input.replace(ROOT_PLACEHOLDER, path).replace(
+				VERSION_PLACEHOLDER, Version.JAVA);
+	}
+
+	/**
+	 * Apply the contextualization operation. This consists of replacing the
+	 * string <tt>{@value #ROOT_PLACEHOLDER}</tt> with the real root of the
+	 * webapp.
+	 * 
+	 * @param ui
+	 *            Where to get information about the URL used to access the
+	 *            webapp.
+	 * @param input
+	 *            the string to contextualize
+	 * @return the contextualized string
+	 */
+	public String contextualize(UriInfo ui, String input) {
+		// Hack to work around bizarre CXF bug
+		String baseuri = ui.getBaseUri().toString().replace("%2D", "-");
+		if (baseuri.endsWith("/"))
+			baseuri = baseuri.substring(0, baseuri.length() - 1);
+		return contextualize(input).replace(BASE_PLACEHOLDER, baseuri);
+	}
+
+	private ServletContext context;
+
+	@Override
+	public void setServletContext(ServletContext servletContext) {
+		context = servletContext;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/DerbyUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/DerbyUtils.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/DerbyUtils.java
new file mode 100644
index 0000000..e4be90b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/DerbyUtils.java
@@ -0,0 +1,84 @@
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Utility class, used to make Derby less broken.
+ * 
+ * @see <a
+ *      href="http://stackoverflow.com/questions/1004327/getting-rid-of-derby-log">
+ *      Getting rid of derby.log </a>
+ * @see <a
+ *      href="http://stackoverflow.com/questions/3339736/set-system-property-with-spring-configuration-file">
+ *      Set system property with Spring configuration file </a>
+ */
+public class DerbyUtils {
+	/**
+	 * A writer that channels things on to the log.
+	 */
+	public static final Writer TO_LOG = new DBLog();
+	// Hack
+	public static final Writer DEV_NULL = TO_LOG;
+}
+
+class DBLog extends Writer {
+	private Log log = LogFactory.getLog("Taverna.Server.Database");
+	private StringBuilder sb = new StringBuilder();
+	private boolean closed = false;
+
+	@Override
+	public void write(char[] cbuf, int off, int len) throws IOException {
+		if (closed)
+			throw new EOFException();
+		if (!log.isInfoEnabled())
+			return;
+		sb.append(cbuf, off, len);
+		while (!closed) {
+			int idx = sb.indexOf("\n"), realIdx = idx;
+			if (idx < 0)
+				break;
+			char ch;
+			while (idx > 0 && ((ch = sb.charAt(idx - 1)) == '\r' || ch == ' ' || ch == '\t'))
+				idx--;
+			if (idx > 0)
+				log.info(sb.substring(0, idx));
+			sb.delete(0, realIdx + 1);
+		}
+	}
+
+	@Override
+	public void flush() throws IOException {
+		if (sb.length() > 0) {
+			log.info(sb.toString());
+			sb = new StringBuilder();
+		}
+	}
+
+	@Override
+	public void close() throws IOException {
+		flush();
+		closed = true;
+		sb = null;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FilenameUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FilenameUtils.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FilenameUtils.java
new file mode 100644
index 0000000..3c39326
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FilenameUtils.java
@@ -0,0 +1,281 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import javax.ws.rs.core.PathSegment;
+
+import org.taverna.server.master.common.DirEntryReference;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * Utility functions for getting entries from directories.
+ * 
+ * @author Donal Fellows
+ */
+public class FilenameUtils {
+	private static final String TYPE_ERROR = "trying to take subdirectory of file";
+	private static final String NO_FILE = "no such directory entry";
+	private static final String NOT_A_FILE = "not a file";
+	private static final String NOT_A_DIR = "not a directory";
+
+	/**
+	 * Get a named directory entry from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param name
+	 *            The name of the directory entry to look up.
+	 * @return The directory entry whose name is equal to the last part of the
+	 *         path; an empty path will retrieve the working directory handle
+	 *         itself.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable.
+	 */
+	public DirectoryEntry getDirEntry(TavernaRun run, String name)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		Directory dir = run.getWorkingDirectory();
+		if (name == null || name.isEmpty())
+			return dir;
+		DirectoryEntry found = dir;
+		boolean mustBeLast = false;
+
+		// Must be nested loops; avoids problems with %-encoded "/" chars
+		for (String bit : name.split("/")) {
+			if (mustBeLast)
+				throw new FilesystemAccessException(TYPE_ERROR);
+			found = getEntryFromDir(bit, dir);
+			dir = null;
+			if (found instanceof Directory) {
+				dir = (Directory) found;
+				mustBeLast = false;
+			} else
+				mustBeLast = true;
+		}
+		return found;
+	}
+
+	/**
+	 * Get a named directory entry from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param d
+	 *            The path segments describing what to look up.
+	 * @return The directory entry whose name is equal to the last part of the
+	 *         path; an empty path will retrieve the working directory handle
+	 *         itself.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable.
+	 */
+	public DirectoryEntry getDirEntry(TavernaRun run, List<PathSegment> d)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		Directory dir = run.getWorkingDirectory();
+		if (d == null || d.isEmpty())
+			return dir;
+		DirectoryEntry found = dir;
+		boolean mustBeLast = false;
+
+		// Must be nested loops; avoids problems with %-encoded "/" chars
+		for (PathSegment segment : d)
+			for (String bit : segment.getPath().split("/")) {
+				if (mustBeLast)
+					throw new FilesystemAccessException(TYPE_ERROR);
+				found = getEntryFromDir(bit, dir);
+				dir = null;
+				if (found instanceof Directory) {
+					dir = (Directory) found;
+					mustBeLast = false;
+				} else
+					mustBeLast = true;
+			}
+		return found;
+	}
+
+	/**
+	 * Get a named directory entry from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param d
+	 *            The directory reference describing what to look up.
+	 * @return The directory entry whose name is equal to the last part of the
+	 *         path in the directory reference; an empty path will retrieve the
+	 *         working directory handle itself.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public DirectoryEntry getDirEntry(TavernaRun run, DirEntryReference d)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		Directory dir = run.getWorkingDirectory();
+		if (d == null || d.path == null || d.path.isEmpty())
+			return dir;
+		DirectoryEntry found = dir;
+		boolean mustBeLast = false;
+
+		for (String bit : d.path.split("/")) {
+			if (mustBeLast)
+				throw new FilesystemAccessException(TYPE_ERROR);
+			found = getEntryFromDir(bit, dir);
+			dir = null;
+			if (found instanceof Directory) {
+				dir = (Directory) found;
+				mustBeLast = false;
+			} else
+				mustBeLast = true;
+		}
+		return found;
+	}
+
+	/**
+	 * Get a named directory entry from a directory.
+	 * 
+	 * @param name
+	 *            The name of the entry; must be "<tt>/</tt>"-free.
+	 * @param dir
+	 *            The directory to look in.
+	 * @return The directory entry whose name is equal to the given name.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable.
+	 */
+	private DirectoryEntry getEntryFromDir(String name, Directory dir)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		if (dir == null)
+			throw new FilesystemAccessException(NO_FILE);
+		for (DirectoryEntry entry : dir.getContents())
+			if (entry.getName().equals(name))
+				return entry;
+		throw new NoDirectoryEntryException(NO_FILE);
+	}
+
+	/**
+	 * Get a named directory from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param d
+	 *            The directory reference describing what to look up.
+	 * @return The directory whose name is equal to the last part of the path in
+	 *         the directory reference; an empty path will retrieve the working
+	 *         directory handle itself.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable, or if the
+	 *             name doesn't refer to a directory.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public Directory getDirectory(TavernaRun run, DirEntryReference d)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		DirectoryEntry dirEntry = getDirEntry(run, d);
+		if (dirEntry instanceof Directory)
+			return (Directory) dirEntry;
+		throw new FilesystemAccessException(NOT_A_DIR);
+	}
+
+	/**
+	 * Get a named directory from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param name
+	 *            The name of the directory to look up.
+	 * @return The directory.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable, or if the
+	 *             name doesn't refer to a directory.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public Directory getDirectory(TavernaRun run, String name)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		DirectoryEntry dirEntry = getDirEntry(run, name);
+		if (dirEntry instanceof Directory)
+			return (Directory) dirEntry;
+		throw new FilesystemAccessException(NOT_A_DIR);
+	}
+
+	/**
+	 * Get a named file from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param d
+	 *            The directory reference describing what to look up.
+	 * @return The file whose name is equal to the last part of the path in the
+	 *         directory reference; an empty path will retrieve the working
+	 *         directory handle itself.
+	 * @throws FilesystemAccessException
+	 *             If the file isn't specified or isn't readable, or if the name
+	 *             doesn't refer to a file.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public File getFile(TavernaRun run, DirEntryReference d)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		DirectoryEntry dirEntry = getDirEntry(run, d);
+		if (dirEntry instanceof File)
+			return (File) dirEntry;
+		throw new FilesystemAccessException(NOT_A_FILE);
+	}
+
+	/**
+	 * Get a named file from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param name
+	 *            The name of the file to look up.
+	 * @return The file whose name is equal to the last part of the path in the
+	 *         directory reference; an empty path will retrieve the working
+	 *         directory handle itself.
+	 * @throws FilesystemAccessException
+	 *             If the file isn't specified or isn't readable, or if the name
+	 *             doesn't refer to a file.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public File getFile(TavernaRun run, String name)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		DirectoryEntry dirEntry = getDirEntry(run, name);
+		if (dirEntry instanceof File)
+			return (File) dirEntry;
+		throw new FilesystemAccessException(NOT_A_FILE);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
new file mode 100644
index 0000000..7f5f92a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
@@ -0,0 +1,34 @@
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import org.apache.cxf.jaxrs.provider.ProviderFactory;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+import org.apache.cxf.phase.Phase;
+
+public class FlushThreadLocalCacheInterceptor extends
+		AbstractPhaseInterceptor<Message> {
+	public FlushThreadLocalCacheInterceptor() {
+		super(Phase.USER_LOGICAL_ENDING);
+	}
+
+	@Override
+	public void handleMessage(Message message) {
+		ProviderFactory.getInstance(message).clearThreadLocalProxies();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/InvocationCounter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/InvocationCounter.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/InvocationCounter.java
new file mode 100644
index 0000000..0600857
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/InvocationCounter.java
@@ -0,0 +1,61 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+
+/**
+ * This class is responsible for counting all invocations of publicly-exposed
+ * methods of the webapp. It's connected to the webapp primarily through an
+ * AspectJ-style pointcut.
+ * 
+ * @author Donal Fellows
+ */
+@Aspect
+public class InvocationCounter {
+	private int count;
+
+	@Before("@annotation(org.taverna.server.master.utils.InvocationCounter.CallCounted)")
+	public synchronized void count() {
+		count++;
+	}
+
+	public synchronized int getCount() {
+		return count;
+	}
+
+	/**
+	 * Mark methods that should be counted by the invocation counter.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@Retention(RUNTIME)
+	@Documented
+	@Target(METHOD)
+	public static @interface CallCounted {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JCECheck.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JCECheck.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JCECheck.java
new file mode 100644
index 0000000..7f248ff
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JCECheck.java
@@ -0,0 +1,73 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static java.lang.Integer.MAX_VALUE;
+import static javax.crypto.Cipher.getMaxAllowedKeyLength;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Trivial bean that checks for whether the JCE policy files that allow
+ * unlimited strength security are present, and warns in the log if not.
+ * 
+ * @author Donal Fellows
+ */
+public class JCECheck {
+	/**
+	 * Write a message to the log that says whether an unlimited strength
+	 * {@linkplain #Cipher cipher} is present. This is the official proxy for
+	 * whether the unlimited strength JCE policy files have been installed; if
+	 * absent, the message is logged as a warning, otherwise it is just
+	 * informational.
+	 */
+	@PostConstruct
+	public void checkForUnlimitedJCE() {
+		Log log = getLog("Taverna.Server.Utils");
+
+		try {
+			if (getMaxAllowedKeyLength("AES") < MAX_VALUE)
+				log.warn("maximum key length very short; unlimited "
+						+ "strength JCE policy files maybe missing");
+			else
+				log.info("unlimited strength JCE policy in place");
+		} catch (GeneralSecurityException e) {
+			log.warn("problem computing key length limits!", e);
+		}
+	}
+
+	/**
+	 * @return Whether the unlimited strength JCE policy files are present (or
+	 *         rather whether an unlimited strength {@linkplain #Cipher cipher}
+	 *         is permitted).
+	 */
+	public boolean isUnlimitedStrength() {
+		try {
+			return getMaxAllowedKeyLength("AES") == MAX_VALUE;
+		} catch (NoSuchAlgorithmException e) {
+			return false;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JDOSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JDOSupport.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JDOSupport.java
new file mode 100644
index 0000000..96f6a11
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/JDOSupport.java
@@ -0,0 +1,285 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.WeakHashMap;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.PreDestroy;
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.Query;
+import javax.jdo.Transaction;
+
+import org.apache.commons.logging.Log;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * Simple support class that wraps up and provides access to the correct parts
+ * of JDO.
+ * 
+ * @author Donal Fellows
+ * 
+ * @param &lt;T&gt; The context class that the subclass will be working with.
+ */
+public abstract class JDOSupport<T> {
+	private Class<T> contextClass;
+	private PersistenceManagerBuilder pmb;
+
+	/**
+	 * Instantiate this class, supplying it a handle to the class that will be
+	 * used to provide context for queries and accesses.
+	 * 
+	 * @param contextClass
+	 *            Must match the type parameter to the class itself.
+	 */
+	protected JDOSupport(@Nonnull Class<T> contextClass) {
+		this.contextClass = contextClass;
+	}
+
+	/**
+	 * @param persistenceManagerBuilder
+	 *            The JDO engine to use for managing persistence.
+	 */
+	@Required
+	public void setPersistenceManagerBuilder(
+			PersistenceManagerBuilder persistenceManagerBuilder) {
+		pmb = persistenceManagerBuilder;
+	}
+
+	private PersistenceManager pm() {
+		if (isPersistent())
+			return pmb.getPersistenceManager();
+		return null;
+	}
+
+	/**
+	 * Has this class actually been configured with a persistence manager by
+	 * Spring?
+	 * 
+	 * @return Whether there is a persistence manager installed.
+	 */
+	protected boolean isPersistent() {
+		return pmb != null;
+	}
+
+	/**
+	 * Get an instance of a query in JDOQL.
+	 * 
+	 * @param filter
+	 *            The filter part of the query.
+	 * @return The query, which should be executed to retrieve the results.
+	 */
+	@Nonnull
+	protected Query<T> query(@Nonnull String filter) {
+		return pm().newQuery(contextClass, filter);
+	}
+
+	/**
+	 * Get an instance of a named query attached to the context class (as an
+	 * annotation). Note that the result is a <i>raw</i> {@link Query} because
+	 * not all queries return instances of the context class.
+	 * 
+	 * @param name
+	 *            The name of the query.
+	 * @return The query, which should be executed to retrieve the results.
+	 * @see javax.jdo.annotations.Query
+	 */
+	@Nonnull
+	@SuppressWarnings("rawtypes")
+	protected Query namedQuery(@Nonnull String name) {
+		return pm().newNamedQuery(contextClass, name);
+	}
+
+	/**
+	 * Make an instance of the context class persist in the database. It's
+	 * identity must not already exist.
+	 * 
+	 * @param value
+	 *            The instance to persist.
+	 * @return The persistence-coupled instance.
+	 */
+	@Nullable
+	protected T persist(@Nullable T value) {
+		if (value == null)
+			return null;
+		return pm().makePersistent(value);
+	}
+
+	/**
+	 * Make a non-persistent (i.e., will hold its value past the end of the
+	 * transaction) copy of a persistence-coupled instance of the context class.
+	 * 
+	 * @param value
+	 *            The value to decouple.
+	 * @return The non-persistent copy.
+	 */
+	@Nullable
+	protected T detach(@Nullable T value) {
+		if (value == null)
+			return null;
+		return pm().detachCopy(value);
+	}
+
+	/**
+	 * Look up an instance of the context class by its identity.
+	 * 
+	 * @param id
+	 *            The identity of the object.
+	 * @return The instance, which is persistence-coupled.
+	 */
+	@Nullable
+	protected T getById(Object id) {
+		try {
+			return pm().getObjectById(contextClass, id);
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/**
+	 * Delete a persistence-coupled instance of the context class.
+	 * 
+	 * @param value
+	 *            The value to delete.
+	 */
+	protected void delete(@Nullable T value) {
+		if (value != null)
+			pm().deletePersistent(value);
+	}
+
+	/**
+	 * Manages integration of JDO transactions with Spring.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@Aspect
+	public static class TransactionAspect {
+		private Object lock = new Object();
+		private Log log = getLog("Taverna.Server.Utils");
+		private volatile int txid;
+
+		@Around(value = "@annotation(org.taverna.server.master.utils.JDOSupport.WithinSingleTransaction) && target(support)", argNames = "support")
+		Object applyTransaction(ProceedingJoinPoint pjp, JDOSupport<?> support)
+				throws Throwable {
+			synchronized (lock) {
+				PersistenceManager pm = support.pm();
+				int id = ++txid;
+				Transaction tx = (pm == null) ? null : pm.currentTransaction();
+				if (tx != null && tx.isActive())
+					tx = null;
+				if (tx != null) {
+					if (log.isDebugEnabled())
+						log.debug("starting transaction #" + id);
+					tx.begin();
+				}
+				try {
+					Object result = pjp.proceed();
+					if (tx != null) {
+						tx.commit();
+						if (log.isDebugEnabled())
+							log.debug("committed transaction #" + id);
+					}
+					tx = null;
+					return result;
+				} catch (Throwable t) {
+					try {
+						if (tx != null) {
+							tx.rollback();
+							if (log.isDebugEnabled())
+								log.debug("rolled back transaction #" + id);
+						}
+					} catch (JDOException e) {
+						log.warn("rollback failed unexpectedly", e);
+					}
+					throw t;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Mark a method (of a subclass of {@link JDOSupport}) as having a
+	 * transaction wrapped around it. The transactions are managed correctly in
+	 * the multi-threaded case.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@Target(METHOD)
+	@Retention(RUNTIME)
+	@Documented
+	public @interface WithinSingleTransaction {
+	}
+
+	/**
+	 * Manages {@linkplain PersistenceManager persistence managers} in a way
+	 * that doesn't cause problems when the web application is unloaded.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public static class PersistenceManagerBuilder {
+		private PersistenceManagerFactory pmf;
+		private WeakHashMap<Thread, PersistenceManager> cache = new WeakHashMap<>();
+
+		/**
+		 * @param persistenceManagerFactory
+		 *            The JDO engine to use for managing persistence.
+		 */
+		@Required
+		public void setPersistenceManagerFactory(
+				PersistenceManagerFactory persistenceManagerFactory) {
+			pmf = persistenceManagerFactory;
+		}
+
+		@Nonnull
+		public PersistenceManager getPersistenceManager() {
+			if (cache == null)
+				return pmf.getPersistenceManager();
+			Thread t = Thread.currentThread();
+			PersistenceManager pm = cache.get(t);
+			if (pm == null && pmf != null) {
+				pm = pmf.getPersistenceManager();
+				cache.put(t, pm);
+			}
+			return pm;
+		}
+
+		@PreDestroy
+		void clearThreadCache() {
+			WeakHashMap<Thread, PersistenceManager> cache = this.cache;
+			this.cache = null;
+			for (PersistenceManager pm : cache.values())
+				if (pm != null)
+					pm.close();
+			cache.clear();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/LoggingDerbyAdapter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/LoggingDerbyAdapter.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/LoggingDerbyAdapter.java
new file mode 100644
index 0000000..8bd0506
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/LoggingDerbyAdapter.java
@@ -0,0 +1,154 @@
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static java.lang.System.currentTimeMillis;
+import static java.lang.Thread.sleep;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.sql.DatabaseMetaData;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.datanucleus.store.rdbms.adapter.DerbyAdapter;
+import org.datanucleus.store.rdbms.identifier.IdentifierFactory;
+import org.datanucleus.store.rdbms.key.CandidateKey;
+import org.datanucleus.store.rdbms.key.ForeignKey;
+import org.datanucleus.store.rdbms.key.Index;
+import org.datanucleus.store.rdbms.key.PrimaryKey;
+import org.datanucleus.store.rdbms.sql.SQLTable;
+import org.datanucleus.store.rdbms.table.Column;
+import org.datanucleus.store.rdbms.table.Table;
+import org.datanucleus.store.rdbms.table.TableImpl;
+import org.datanucleus.store.rdbms.table.ViewImpl;
+
+/**
+ * Evil hack to allow logging of the DDL spat out to Derby.
+ * 
+ * @author Donal Fellows
+ */
+public class LoggingDerbyAdapter extends DerbyAdapter {
+	Log log = getLog("Taverna.Server.SQL");
+
+	private StringBuilder ddl = new StringBuilder();
+	private volatile long timeout;
+	private Thread timer;
+
+	private synchronized void logDDL() {
+		if (ddl.length() > 0) {
+			log.info("Data definition language:\n" + ddl);
+			ddl.setLength(0);
+		}
+		timer = null;
+	}
+
+	private synchronized void doLog(String item) {
+		ddl.append(item);
+		if (!item.endsWith("\n"))
+			ddl.append('\n');
+		timeout = currentTimeMillis() + 5000;
+		if (timer == null)
+			timer = new OneShotThread("DDL logger timeout", new Runnable() {
+				@Override
+				public void run() {
+					try {
+						while (timeout > currentTimeMillis())
+							sleep(1000);
+					} catch (InterruptedException e) {
+						// Ignore
+					}
+					logDDL();
+				}
+			});
+	}
+
+	/**
+	 * Creates an Apache Derby adapter based on the given metadata which logs
+	 * the DDL it creates.
+	 */
+	public LoggingDerbyAdapter(DatabaseMetaData metadata) {
+		super(metadata);
+	}
+
+	@Override
+	public String getCreateTableStatement(TableImpl table, Column[] columns,
+			Properties props, IdentifierFactory factory) {
+		String statement = super.getCreateTableStatement(table, columns, props,
+				factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getCreateIndexStatement(Index index, IdentifierFactory factory) {
+		String statement = super.getCreateIndexStatement(index, factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getAddCandidateKeyStatement(CandidateKey ck,
+			IdentifierFactory factory) {
+		String statement = super.getAddCandidateKeyStatement(ck, factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getAddPrimaryKeyStatement(PrimaryKey pk,
+			IdentifierFactory factory) {
+		String statement = super.getAddPrimaryKeyStatement(pk, factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getAddColumnStatement(Table table, Column col) {
+		String statement = super.getAddColumnStatement(table, col);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getAddForeignKeyStatement(ForeignKey fk,
+			IdentifierFactory factory) {
+		String statement = super.getAddForeignKeyStatement(fk, factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getDeleteTableStatement(SQLTable tbl) {
+		String statement = super.getDeleteTableStatement(tbl);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getDropTableStatement(Table table) {
+		String statement = super.getDropTableStatement(table);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getDropViewStatement(ViewImpl view) {
+		String statement = super.getDropViewStatement(view);
+		doLog(statement);
+		return statement;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/OneShotThread.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/OneShotThread.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/OneShotThread.java
new file mode 100644
index 0000000..32cca5a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/OneShotThread.java
@@ -0,0 +1,26 @@
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+public class OneShotThread extends Thread {
+	public OneShotThread(String name, Runnable target) {
+		super(target, name);
+		setContextClassLoader(null);
+		setDaemon(true);
+		start();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RestUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RestUtils.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RestUtils.java
new file mode 100644
index 0000000..d69612e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RestUtils.java
@@ -0,0 +1,45 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.core.Response;
+
+/**
+ * Utilities that make it easier to write REST services.
+ * 
+ * @author Donal Fellows
+ */
+public class RestUtils {
+	/**
+	 * Generate a response to an HTTP OPTIONS request.
+	 * 
+	 * @param methods
+	 *            The state-changing methods supported, if any.
+	 * @return the required response
+	 * @see OPTIONS
+	 */
+	public static Response opt(String... methods) {
+		StringBuilder sb = new StringBuilder("GET,");
+		for (String m : methods)
+			sb.append(m).append(",");
+		sb.append("HEAD,OPTIONS");
+		return Response.ok().header("Allow", sb.toString()).entity("").build();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RuntimeExceptionWrapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RuntimeExceptionWrapper.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RuntimeExceptionWrapper.java
new file mode 100644
index 0000000..333febe
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/RuntimeExceptionWrapper.java
@@ -0,0 +1,50 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.taverna.server.master.exceptions.GeneralFailureException;
+
+/**
+ * Aspect used to convert {@linkplain RuntimeException runtime exceptions} into
+ * a form that can be nicely conveyed to the outside world as HTTP errors.
+ * 
+ * @author Donal Fellows
+ */
+@Aspect
+public class RuntimeExceptionWrapper {
+	/**
+	 * Map an unexpected exception to one that can be correctly reported as a
+	 * problem.
+	 * 
+	 * @param exn
+	 *            The runtime exception being trapped.
+	 * @throws GeneralFailureException
+	 *             The known exception type that it is mapped to.
+	 */
+	@AfterThrowing(pointcut = "execution(* org.taverna.server.master.rest..*(..)) && !bean(*Provider.*)", throwing = "exn")
+	public void wrapRuntimeException(RuntimeException exn)
+			throws GeneralFailureException {
+		// Exclude security-related exceptions
+		if (exn.getClass().getName().startsWith("org.springframework.security."))
+			return;
+		throw new GeneralFailureException(exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/UsernamePrincipal.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/UsernamePrincipal.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/UsernamePrincipal.java
new file mode 100644
index 0000000..25cf64f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/UsernamePrincipal.java
@@ -0,0 +1,82 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import java.io.Serializable;
+import java.security.Principal;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.userdetails.UserDetails;
+
+/**
+ * A simple serializable principal that just records the name.
+ * 
+ * @author Donal Fellows
+ */
+public class UsernamePrincipal implements Principal, Serializable {
+	private static final long serialVersionUID = 2703493248562435L;
+	public UsernamePrincipal(String username) {
+		this.name = username;
+	}
+
+	public UsernamePrincipal(Principal other) {
+		this.name = other.getName();
+	}
+
+	public UsernamePrincipal(Authentication auth) {
+		this(auth.getPrincipal());
+	}
+
+	public UsernamePrincipal(Object principal) {
+		if (principal instanceof Principal)
+			this.name = ((Principal) principal).getName();
+		else if (principal instanceof String)
+			this.name = (String) principal;
+		else if (principal instanceof UserDetails)
+			this.name = ((UserDetails) principal).getUsername();
+		else
+			this.name = principal.toString();
+	}
+
+	private String name;
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public String toString() {
+		return "Principal<" + name + ">";
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof Principal) {
+			Principal p = (Principal) o;
+			return name.equals(p.getName());
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return name.hashCode();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
new file mode 100644
index 0000000..1bd2a95
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
@@ -0,0 +1,81 @@
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.apache.cxf.common.util.UrlUtils.parseQueryString;
+import static org.apache.cxf.message.Message.HTTP_REQUEST_METHOD;
+import static org.apache.cxf.message.Message.QUERY_STRING;
+import static org.apache.cxf.message.Message.REQUEST_URL;
+import static org.apache.cxf.phase.Phase.READ;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.cxf.binding.soap.interceptor.EndpointSelectionInterceptor;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+
+
+/**
+ * Thunk for TAVSERV-293.
+ * 
+ * @author Donal Fellows (based on work by Daniel Hagen)
+ */
+public class WSDLHeadOptionsInterceptor extends
+		AbstractPhaseInterceptor<Message> {
+	public static final Log log = getLog("Taverna.Server.Utils");
+
+	public WSDLHeadOptionsInterceptor() {
+		super(READ);
+		getAfter().add(EndpointSelectionInterceptor.class.getName());
+	}
+
+	@Override
+	public void handleMessage(Message message) throws Fault {
+		String method = (String) message.get(HTTP_REQUEST_METHOD);
+		String query = (String) message.get(QUERY_STRING);
+
+		if (("HEAD".equals(method) || "OPTIONS".equals(method))
+				&& query != null && !query.trim().isEmpty()
+				&& isRecognizedQuery(query)) {
+			log.debug("adjusting message request method " + method + " for "
+					+ message.get(REQUEST_URL) + " to GET");
+			message.put(HTTP_REQUEST_METHOD, "GET");
+		}
+	}
+
+	/*
+	 * Stolen from http://permalink.gmane.org/gmane.comp.apache.cxf.user/20037
+	 * which is itself in turn stolen from
+	 * org.apache.cxf.frontend.WSDLGetInterceptor.isRecognizedQuery
+	 */
+	/**
+	 * Is this a query for WSDL or XSD relating to it?
+	 * 
+	 * @param query
+	 *            The query string to check
+	 * @return If the query is one to handle.
+	 * @see org.apache.cxf.frontend.WSDLGetInterceptor#isRecognizedQuery(Map,String,String,org.apache.cxf.service.model.EndpointInfo)
+	 *      WSDLGetInterceptor
+	 */
+	private boolean isRecognizedQuery(String query) {
+		Map<String, String> map = parseQueryString(query);
+		return map.containsKey("wsdl") || map.containsKey("xsd");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WebappAwareDataSource.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WebappAwareDataSource.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WebappAwareDataSource.java
new file mode 100644
index 0000000..24246b5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/WebappAwareDataSource.java
@@ -0,0 +1,147 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static java.lang.Thread.currentThread;
+import static java.sql.DriverManager.deregisterDriver;
+import static java.sql.DriverManager.getDrivers;
+import static org.taverna.server.master.utils.Contextualizer.ROOT_PLACEHOLDER;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Enumeration;
+
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * Add some awareness of the context so that we can locate databases internally
+ * to the webapp.
+ * 
+ * @author Donal Fellows
+ */
+public class WebappAwareDataSource extends BasicDataSource {
+	Log log = LogFactory.getLog("Taverna.Server.Utils");
+	private transient boolean init;
+	private Contextualizer ctxt;
+	private String shutdownUrl;
+
+	@Required
+	public void setContextualizer(Contextualizer ctxt) {
+		this.ctxt = ctxt;
+	}
+
+	/**
+	 * A JDBC connection URL to use on shutting down the database. If not set,
+	 * do nothing special.
+	 * 
+	 * @param url
+	 */
+	public void setShutdownUrl(String url) {
+		shutdownUrl = url;
+	}
+
+	private void doInit() {
+		synchronized (this) {
+			if (!init) {
+				setDriverClassLoader(currentThread().getContextClassLoader());
+				String url = getUrl();
+				if (url.contains(ROOT_PLACEHOLDER)) {
+					String newurl = ctxt.contextualize(url);
+					setUrl(newurl);
+					log.info("mapped " + url + " to " + newurl);
+				} else {
+					log.info("did not find " + ROOT_PLACEHOLDER + " in " + url);
+				}
+				init = true;
+			}
+		}
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=- HOOKS -=-=-=-=-=-=-=-=-=-=-
+
+	@Override
+	public Connection getConnection() throws SQLException {
+		doInit();
+		return super.getConnection();
+	}
+
+	@Override
+	public void setLogWriter(PrintWriter pw) throws SQLException {
+		doInit();
+		super.setLogWriter(pw);
+	}
+
+	@Override
+	public void setLoginTimeout(int num) throws SQLException {
+		doInit();
+		super.setLoginTimeout(num);
+	}
+
+	@Override
+	public PrintWriter getLogWriter() throws SQLException {
+		doInit();
+		return super.getLogWriter();
+	}
+
+	@Override
+	public int getLoginTimeout() throws SQLException {
+		doInit();
+		return super.getLoginTimeout();
+	}
+
+	@PreDestroy
+	void realClose() {
+		try {
+			close();
+		} catch (SQLException e) {
+			log.warn("problem shutting down DB connection", e);
+		}
+		try {
+			if (shutdownUrl != null)
+				DriverManager.getConnection(ctxt.contextualize(shutdownUrl));
+		} catch (SQLException e) {
+			// Expected; ignore it
+		}
+		log = null;
+		dropDriver();
+	}
+
+	private void dropDriver() {
+		Enumeration<Driver> drivers = getDrivers();
+		while (drivers.hasMoreElements()) {
+			Driver d = drivers.nextElement();
+			if (d.getClass().getClassLoader() == getDriverClassLoader()
+					&& d.getClass().getName().equals(getDriverClassName())) {
+				try {
+					deregisterDriver(d);
+				} catch (SQLException e) {
+				}
+				break;
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/X500Utils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/X500Utils.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/X500Utils.java
new file mode 100644
index 0000000..d258079
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/X500Utils.java
@@ -0,0 +1,120 @@
+/*
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */
+
+import static javax.security.auth.x500.X500Principal.RFC2253;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.PreDestroy;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Support class that factors out some of the messier parts of working with
+ * X.500 identities and X.509 certificates.
+ * 
+ * @author Donal Fellows
+ */
+public class X500Utils {
+	private Log log = LogFactory.getLog("Taverna.Server.Utils");
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	private static final char DN_SEPARATOR = ',';
+	private static final char DN_ESCAPE = '\\';
+	private static final char DN_QUOTE = '"';
+
+	/**
+	 * Parse the DN from the Principal and extract the CN field.
+	 * 
+	 * @param id
+	 *            The identity to extract the distinguished name from.
+	 * @param fields
+	 *            The names to look at when finding the field to return. Each
+	 *            should be an upper-cased string.
+	 * @return The common-name part of the distinguished name, or the literal
+	 *         string "<tt>none</tt>" if there is no CN.
+	 */
+	public String getName(X500Principal id, String... fields) {
+		String dn = id.getName(RFC2253);
+
+		int i = 0;
+		int startIndex = 0;
+		boolean ignoreThisChar = false;
+		boolean inQuotes = false;
+		Map<String, String> tokenized = new HashMap<>();
+
+		for (i = 0; i < dn.length(); i++)
+			if (ignoreThisChar)
+				ignoreThisChar = false;
+			else if (dn.charAt(i) == DN_QUOTE)
+				inQuotes = !inQuotes;
+			else if (inQuotes)
+				continue;
+			else if (dn.charAt(i) == DN_ESCAPE)
+				ignoreThisChar = true;
+			else if ((dn.charAt(i) == DN_SEPARATOR) && !ignoreThisChar) {
+				storeDNField(tokenized, dn.substring(startIndex, i).trim()
+						.split("=", 2));
+				startIndex = i + 1;
+			}
+		if (inQuotes || ignoreThisChar)
+			log.warn("was parsing invalid DN format");
+		// Add last token - after the last delimiter
+		storeDNField(tokenized, dn.substring(startIndex).trim().split("=", 2));
+
+		for (String field : fields) {
+			String value = tokenized.get(field);
+			if (value != null)
+				return value;
+		}
+		return "none";
+	}
+
+	private void storeDNField(Map<String, String> container, String[] split) {
+		if (split == null || split.length != 2)
+			return;
+		String key = split[0].toUpperCase();
+		if (container.containsKey(key))
+			log.warn("duplicate field in DN: " + key);
+		// LATER: Should the field be de-quoted?
+		container.put(key, split[1]);
+	}
+
+	/**
+	 * Get the serial number from a certificate as a hex string.
+	 * 
+	 * @param cert
+	 *            The certificate to extract from.
+	 * @return A hex string, in upper-case.
+	 */
+	public String getSerial(X509Certificate cert) {
+		return new BigInteger(1, cert.getSerialNumber().toByteArray())
+				.toString(16).toUpperCase();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/package-info.java
new file mode 100644
index 0000000..64a9f68
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/utils/package-info.java
@@ -0,0 +1,23 @@
+/*
+ */
+/**
+ * Miscellaneous utility classes. Includes aspects that might be attached
+ * for purposes such as transaction management and invocation tracking.
+ */
+package org.taverna.server.master.utils;
+/*
+ * 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.
+ */



[09/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java
deleted file mode 100644
index 8404ead..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- */
-/**
- * This package contains type handlers for the RESTful interface to Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER_REST, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "port", namespaceURI = DATA),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.port_description.Namespaces.DATA;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java
deleted file mode 100644
index d35dc7b..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- */
-/**
- * This package contains the RESTful interface to Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER_REST, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "port", namespaceURI = DATA),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.port_description.Namespaces.DATA;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java
deleted file mode 100644
index 752c6b1..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- */
-package org.taverna.server.master.soap;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.net.URI;
-
-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.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.common.DirEntryReference;
-
-/**
- * A more Taverna-friendly version of the directory entry descriptor classes.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "DirectoryEntry")
-@XmlRootElement(name = "entry")
-@XmlSeeAlso({ DirEntry.File.class, DirEntry.Directory.class })
-public class DirEntry {
-	/** A link to the entry. Ignored on input. */
-	@XmlAttribute(name = "href", namespace = XLINK)
-	@XmlSchemaType(name = "anyURI")
-	public URI link;
-	@XmlAttribute
-	public String name;
-	@XmlElement(required = true)
-	public String path;
-
-	/**
-	 * A file in a directory.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlType(name = "FileDirEntry")
-	@XmlRootElement(name = "file")
-	public static class File extends DirEntry {
-	}
-
-	/**
-	 * A directory in a directory. That is, a sub-directory.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlType(name = "DirectoryDirEntry")
-	@XmlRootElement(name = "dir")
-	public static class Directory extends DirEntry {
-	}
-
-	/**
-	 * Converts from the "common" format to the subclasses of this class.
-	 * 
-	 * @param deref
-	 *            The "common" format handle to convert.
-	 * @return The converted handle
-	 */
-	public static DirEntry convert(DirEntryReference deref) {
-		DirEntry result;
-		if (deref instanceof DirEntryReference.DirectoryReference)
-			result = new Directory();
-		else if (deref instanceof DirEntryReference.FileReference)
-			result = new File();
-		else
-			result = new DirEntry();
-		result.link = deref.link;
-		result.name = deref.name;
-		result.path = deref.path;
-		return result;
-	}
-
-	/**
-	 * Converts to the "common" format from the subclasses of this class.
-	 * 
-	 * @param deref
-	 *            The subclass of this class to convert.
-	 * @return The converted reference.
-	 */
-	public static DirEntryReference convert(DirEntry de) {
-		DirEntryReference result;
-		if (de instanceof Directory)
-			result = new DirEntryReference.DirectoryReference();
-		else if (de instanceof File)
-			result = new DirEntryReference.FileReference();
-		else
-			result = new DirEntryReference();
-		result.link = de.link;
-		result.name = de.name;
-		result.path = de.path;
-		return result;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java
deleted file mode 100644
index fa9978b..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- */
-package org.taverna.server.master.soap;
-/*
- * 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.
- */
-
-import static java.lang.Math.min;
-import static java.lang.System.arraycopy;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import javax.activation.DataHandler;
-import javax.activation.DataSource;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlMimeType;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-/**
- * An MTOM-capable description of how to transfer the contents of a file.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "FileContents")
-public class FileContents {
-	@XmlElement
-	public String name;
-	@XmlMimeType("application/octet-stream") // JAXB bug: must be this
-	public DataHandler fileData;
-
-	/**
-	 * Initialize the contents of this descriptor from the given file and
-	 * content type.
-	 * 
-	 * @param file
-	 *            The file that is to be reported.
-	 * @param contentType
-	 *            The estimated content type of the file.
-	 */
-	public void setFile(File file, String contentType) {
-		name = file.getFullName();
-		fileData = new DataHandler(new TavernaFileSource(file, contentType));
-	}
-
-	/**
-	 * Write the content described by this class to the specified file.
-	 * @param file The file to write to; must already exist.
-	 * @throws IOException
-	 * @throws FilesystemAccessException
-	 */
-	public void writeToFile(File file) throws IOException,
-			FilesystemAccessException {
-		try (InputStream is = fileData.getInputStream()) {
-			byte[] buf = new byte[65536];
-			file.setContents(new byte[0]);
-			while (true) {
-				int len = is.read(buf);
-				if (len <= 0)
-					return;
-				if (len == buf.length)
-					file.appendContents(buf);
-				else {
-					byte[] shortbuf = new byte[len];
-					arraycopy(buf, 0, shortbuf, 0, len);
-					file.appendContents(shortbuf);
-				}
-			}
-		}
-	}
-}
-
-/**
- * A data source that knows how to communicate with the Taverna Server back-end.
- * 
- * @author Donal Fellows
- */
-class TavernaFileSource implements DataSource {
-	TavernaFileSource(File f, String type) {
-		this.f = f;
-		this.type = type;
-	}
-
-	private final File f;
-	private final String type;
-
-	@Override
-	public String getContentType() {
-		return type;
-	}
-
-	@Override
-	public String getName() {
-		return f.getName();
-	}
-
-	@Override
-	public InputStream getInputStream() throws IOException {
-		final File f = this.f;
-		return new InputStream() {
-			private int idx;
-
-			@Override
-			public int read(byte[] b, int off, int len) throws IOException {
-				byte[] r;
-				try {
-					r = f.getContents(idx, len);
-				} catch (FilesystemAccessException e) {
-					throw new IOException(e);
-				}
-				if (r == null)
-					return -1;
-				len = min(len, r.length);
-				arraycopy(r, 0, b, off, len);
-				idx += len;
-				return len;
-			}
-
-			@Override
-			public int read() throws IOException {
-				byte[] r;
-				try {
-					r = f.getContents(idx, 1);
-				} catch (FilesystemAccessException e) {
-					throw new IOException(e);
-				}
-				if (r == null)
-					return -1;
-				idx++;
-				return r[0];
-			}
-		};
-	}
-
-	@Override
-	public OutputStream getOutputStream() throws IOException {
-		final File f = this.f;
-		return new OutputStream() {
-			private boolean append = false;
-
-			@Override
-			public void write(int b) throws IOException {
-				write(new byte[] { (byte) b });
-			}
-
-			@Override
-			public void write(byte[] b) throws IOException {
-				try {
-					if (append)
-						f.appendContents(b);
-					else
-						f.setContents(b);
-					append = true;
-				} catch (FilesystemAccessException e) {
-					throw new IOException(e);
-				}
-			}
-
-			@Override
-			public void write(byte[] b, int off, int len) throws IOException {
-				byte[] ary = new byte[len];
-				arraycopy(b, off, ary, 0, len);
-				write(ary);
-			}
-		};
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java
deleted file mode 100644
index 6568ab2..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- */
-package org.taverna.server.master.soap;
-/*
- * 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.
- */
-
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.common.Permission;
-
-/**
- * The list of permissions to access a workflow run of users <i>other than the
- * owner</i>. This class exists to support the JAXB mapping.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "PermissionList")
-@XmlRootElement(name = "permissionList")
-public class PermissionList {
-	/**
-	 * The type of a single mapped permission. This class exists to support the
-	 * JAXB mapping.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlType(name = "")
-	public static class SinglePermissionMapping {
-		public SinglePermissionMapping() {
-		}
-
-		public SinglePermissionMapping(String user, Permission permission) {
-			this.userName = user;
-			this.permission = permission;
-		}
-
-		/** The name of the user that this talks about. */
-		public String userName;
-		/** The permission level that the user is granted. */
-		public Permission permission;
-	}
-
-	/** The list of (non-default) permissions granted. */
-	@XmlElement
-	public List<SinglePermissionMapping> permission;
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java
deleted file mode 100644
index f41539c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java
+++ /dev/null
@@ -1,1566 +0,0 @@
-/*
- */
-package org.taverna.server.master.soap;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Roles.USER;
-
-import java.net.URI;
-import java.util.Date;
-import java.util.List;
-
-import javax.annotation.security.RolesAllowed;
-import javax.jws.WebMethod;
-import javax.jws.WebParam;
-import javax.jws.WebResult;
-import javax.jws.WebService;
-import javax.xml.bind.annotation.XmlElement;
-
-import org.apache.cxf.annotations.WSDLDocumentation;
-import org.apache.taverna.server.usagerecord.JobUsageRecord;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.common.InputDescription;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoCredentialException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.NotOwnerException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.rest.TavernaServerREST;
-import org.taverna.server.port_description.OutputDescription;
-
-/**
- * The SOAP service interface to Taverna 3 Server.
- * 
- * @author Donal Fellows
- * @see TavernaServerREST
- */
-@RolesAllowed(USER)
-@WebService(name = "tavernaService", targetNamespace = SERVER_SOAP)
-@WSDLDocumentation("The SOAP service interface to Taverna " + Version.JAVA
-		+ " Server.")
-public interface TavernaServerSOAP {
-	/**
-	 * Make a run for a particular workflow.
-	 * 
-	 * @param workflow
-	 *            The workflow to instantiate.
-	 * @return Annotated handle for created run.
-	 * @throws NoUpdateException
-	 * @throws NoCreateException
-	 */
-	@WebResult(name = "Run")
-	@WSDLDocumentation("Make a run for a particular workflow.")
-	RunReference submitWorkflow(
-			@WebParam(name = "workflow") @XmlElement(required = true) Workflow workflow)
-					throws NoUpdateException, NoCreateException;
-
-	/**
-	 * Make a run for a particular workflow.
-	 * 
-	 * @param workflow
-	 *            The workflow to instantiate.
-	 * @return Annotated handle for created run.
-	 * @throws NoUpdateException
-	 * @throws NoCreateException
-	 */
-	@WebResult(name = "Run")
-	@WSDLDocumentation("Make a run for a particular workflow.")
-	RunReference submitWorkflowMTOM(
-			@WebParam(name = "workflow") @XmlElement(required = true) WrappedWorkflow workflow)
-			throws NoUpdateException;
-
-	/**
-	 * Make a run for a particular workflow, where that workflow will be
-	 * downloaded from elsewhere. The URI <i>must</i> be publicly readable.
-	 * 
-	 * @param workflowURI
-	 *            The URI to the workflow to instantiate.
-	 * @return Annotated handle for created run.
-	 * @throws NoUpdateException
-	 * @throws NoCreateException
-	 */
-	@WebResult(name = "Run")
-	@WSDLDocumentation("Make a run for a particular workflow where that "
-			+ "workflow is given by publicly readable URI.")
-	RunReference submitWorkflowByURI(
-			@WebParam(name = "workflowURI") @XmlElement(required = true) URI workflowURI)
-			throws NoCreateException, NoUpdateException;
-
-	/**
-	 * Get the list of existing runs owned by the user.
-	 * 
-	 * @return Annotated handle list.
-	 */
-	@WebResult(name = "Run")
-	@WSDLDocumentation("Get the list of existing runs owned by the user.")
-	RunReference[] listRuns();
-
-	/**
-	 * Get the upper limit on the number of runs that the user may create at
-	 * once.
-	 * 
-	 * @return The limit. <b>NB:</b> the number currently operating may be
-	 *         larger, but in that case no further runs can be made until some
-	 *         of the old ones are destroyed.
-	 */
-	@WebResult(name = "MaxSimultaneousRuns")
-	@WSDLDocumentation("Get the upper limit on the number of runs that the user may create at once.")
-	int getServerMaxRuns();
-
-	/**
-	 * Get the list of allowed workflows. If the list is empty, <i>any</i>
-	 * workflow may be used.
-	 * 
-	 * @return A list of workflow documents.
-	 */
-	@WebMethod(operationName = "getPermittedWorkflowURIs")
-	@WebResult(name = "PermittedWorkflowURI")
-	@WSDLDocumentation("Get the list of URIs to allowed workflows. If the list is empty, any workflow may be used including those not submitted via URI.")
-	URI[] getServerWorkflows();
-
-	/**
-	 * Get the list of allowed event listeners.
-	 * 
-	 * @return A list of listener names.
-	 */
-	@WebMethod(operationName = "getPermittedListenerTypes")
-	@WebResult(name = "PermittedListenerType")
-	@WSDLDocumentation("Get the list of allowed types of event listeners.")
-	String[] getServerListeners();
-
-	/**
-	 * Get the list of notification fabrics.
-	 * 
-	 * @return A list of listener names.
-	 */
-	@WebMethod(operationName = "getEnabledNotificationFabrics")
-	@WebResult(name = "EnabledNotifierFabric")
-	@WSDLDocumentation("Get the list of notification fabrics. Each is a URI scheme.")
-	String[] getServerNotifiers();
-
-	@WebMethod(operationName = "getCapabilities")
-	@WebResult(name = "Capabilities")
-	@WSDLDocumentation("Get the workflow execution capabilities of this "
-			+ "Taverna Server instance.")
-	List<Capability> getServerCapabilities();
-
-	/**
-	 * Destroy a run immediately. This might or might not actually relinquish
-	 * resources; that's up to the service implementation and deployment.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the lifetime of the
-	 *             run.
-	 */
-	@WSDLDocumentation("Destroy a run immediately.")
-	void destroyRun(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, NoUpdateException;
-
-	/**
-	 * Get the workflow document used to create the given run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The workflow document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "CreationWorkflow")
-	@WSDLDocumentation("Get the workflow document used to create the given run.")
-	Workflow getRunWorkflow(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the workflow document used to create the given run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The workflow document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "CreationWorkflow")
-	@WSDLDocumentation("Get the workflow document used to create the given run.")
-	WrappedWorkflow getRunWorkflowMTOM(
-			@WebParam(name = "runName") String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get a description of the profiles supported by the workflow document used
-	 * to create the given run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return A description of the supported profiles.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Profiles")
-	@WSDLDocumentation("Get a description of the profiles supported by the workflow document used to create the given run.")
-	ProfileList getRunWorkflowProfiles(
-			@WebParam(name = "runName") String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the descriptive name of the workflow run. The descriptive name
-	 * carries no deep information.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The descriptive name of the run.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "DescriptiveName")
-	@WSDLDocumentation("Get the descriptive name of the workflow run. Carries no deep information.")
-	String getRunDescriptiveName(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Set the descriptive name of the workflow run. The descriptive name
-	 * carries no deep information.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param descriptiveName
-	 *            The new descriptive name to set. Note that the implementation
-	 *            is allowed to arbitrarily truncate this value.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not permitted to update this run.
-	 */
-	@WSDLDocumentation("Set the descriptive name of the workflow run. Carries no deep information.")
-	void setRunDescriptiveName(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "descriptiveName") @XmlElement(required = true) String descriptiveName)
-			throws UnknownRunException, NoUpdateException;
-
-	/**
-	 * Get the description of the inputs to the workflow run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The input description
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "RunInputDescription")
-	@WSDLDocumentation("Get the description of the inputs currently set up for the given workflow run.")
-	InputDescription getRunInputs(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get a description of what inputs the workflow run <i>expects</i> to
-	 * receive.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The description document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "RunInputDescriptor")
-	@WSDLDocumentation("Get a description of what inputs the given workflow run expects to receive.")
-	org.taverna.server.port_description.InputDescription getRunInputDescriptor(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Tells the run to use the given Baclava file for all inputs.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param fileName
-	 *            The name of the file to use. Must not start with a <tt>/</tt>
-	 *            or contain a <tt>..</tt> element.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws FilesystemAccessException
-	 *             If the filename is illegal.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state
-	 */
-	@WSDLDocumentation("Tells the given run to use the given already-uploaded Baclava file for all inputs.")
-	void setRunInputBaclavaFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "baclavaFileName") String fileName)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, BadStateChangeException;
-
-	/**
-	 * Tells the run to use the given file for input on the given port. This
-	 * overrides any previously set file or value on the port and causes the
-	 * server to forget about using a Baclava file for all inputs.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param portName
-	 *            The port to use the file for.
-	 * @param portFilename
-	 *            The file to use on the port. Must not start with a <tt>/</tt>
-	 *            or contain a <tt>..</tt> element.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws FilesystemAccessException
-	 *             If the filename is illegal.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 * @throws BadPropertyValueException
-	 *             If the input port may not be changed to the contents of the
-	 *             given file.
-	 */
-	@WSDLDocumentation("Tells the given run to use the given file for input on the given port.")
-	void setRunInputPortFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "portName") @XmlElement(required = true) String portName,
-			@WebParam(name = "portFileName") @XmlElement(required = true) String portFilename)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, BadStateChangeException,
-			BadPropertyValueException;
-
-	/**
-	 * Tells the run to use the given value for input on the given port. This
-	 * overrides any previously set file or value on the port and causes the
-	 * server to forget about using a Baclava file for all inputs. Note that
-	 * this is wholly unsuitable for use with binary data.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param portName
-	 *            The port to use the file for.
-	 * @param portValue
-	 *            The literal value to use on the port.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 * @throws BadPropertyValueException
-	 *             If the input port may not be changed to the given literal
-	 *             value.
-	 */
-	@WSDLDocumentation("Tells the given run to use the given literal string value for input on the given port.")
-	void setRunInputPortValue(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "portName") @XmlElement(required = true) String portName,
-			@WebParam(name = "portValue") @XmlElement(required = true) String portValue)
-			throws UnknownRunException, NoUpdateException,
-			BadStateChangeException, BadPropertyValueException;
-
-	/**
-	 * Tells the given run to use the given list delimiter (a single-character
-	 * string value) for splitting the input on the given port. Note that
-	 * nullability of the delimiter is supported here.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param portName
-	 *            The port to set the list delimiter for.
-	 * @param delimiter
-	 *            The single-character value (in range U+00001..U+0007F) to use
-	 *            as the delimiter, or <tt>null</tt> for no delimiter at all.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 * @throws BadPropertyValueException
-	 *             If the delimiter may not be changed to the given literal
-	 *             value.
-	 */
-	@WSDLDocumentation("Tells the given run to use the given list delimiter (a single-character string value) for splitting the input on the given port. Note that nullability of the delimiter is supported here.")
-	void setRunInputPortListDelimiter(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "portName") @XmlElement(required = true) String portName,
-			@WebParam(name = "delimiter") String delimiter)
-			throws UnknownRunException, NoUpdateException,
-			BadStateChangeException, BadPropertyValueException;
-
-	/**
-	 * Get the Baclava file where the output of the run will be written.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The filename, or <tt>null</tt> if the results will be written to
-	 *         a subdirectory <tt>out</tt> of the run's working directory.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "OutputBaclavaFile")
-	@WSDLDocumentation("Get the Baclava file where the output of the run will be written.")
-	String getRunOutputBaclavaFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Set the Baclava file where the output of the run will be written.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param outputFile
-	 *            The filename for the Baclava file, or <tt>null</tt> or the
-	 *            empty string to indicate that the results are to be written to
-	 *            the subdirectory <tt>out</tt> of the run's working directory.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws FilesystemAccessException
-	 *             If the filename is illegal (starts with a <tt>/</tt> or
-	 *             contains a <tt>..</tt> element.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state
-	 */
-	@WSDLDocumentation("Set the Baclava file where the output of the run will be written.")
-	void setRunOutputBaclavaFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "baclavaFileName") String outputFile)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, BadStateChangeException;
-
-	/**
-	 * Return a description of the outputs of a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Description document (higher level than filesystem traverse).
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws BadStateChangeException
-	 *             If the run is in the {@link Status#Initialized Initialized}
-	 *             state
-	 * @throws FilesystemAccessException
-	 *             If there is an exception when accessing the filesystem.
-	 * @throws NoDirectoryEntryException
-	 *             If things are odd in the filesystem.
-	 */
-	@WebResult(name = "OutputDescription")
-	@WSDLDocumentation("Return a description of the outputs of a run. Only known during/after the run.")
-	OutputDescription getRunOutputDescription(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, BadStateChangeException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Get the time when the run will be eligible to be automatically deleted.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return A date at which the expiry will be scheduled. The actual deletion
-	 *         will happen an arbitrary amount of time later (depending on
-	 *         system policy).
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Expiry")
-	@WSDLDocumentation("Get the time when the run will be eligible to be automatically deleted.")
-	Date getRunExpiry(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Set when the run will be eligible to be automatically deleted.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param expiry
-	 *            A date at which the expiry will be scheduled. The actual
-	 *            deletion will happen an arbitrary amount of time later
-	 *            (depending on system policy).
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the lifetime of the
-	 *             run.
-	 */
-	@WSDLDocumentation("Set when the run will be eligible to be automatically deleted.")
-	void setRunExpiry(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "expiry") @XmlElement(required = true) Date expiry)
-			throws UnknownRunException, NoUpdateException;
-
-	/**
-	 * Get the time when the run was created.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The moment when the run was created (modulo some internal
-	 *         overhead).
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "CreationTime")
-	@WSDLDocumentation("Get the time when the run was created.")
-	Date getRunCreationTime(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the time when the run was started.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The moment when the run was started (modulo some internal
-	 *         overhead) or <tt>null</tt> to indicate that it has never started.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "StartTime")
-	@WSDLDocumentation("Get the time when the run was started.")
-	Date getRunStartTime(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the time when the run was detected as having finished.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The moment when the run was believed stopped. Note that this may
-	 *         not be when the run <i>actually</i> finished; promptness of
-	 *         detection depends on many factors.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "FinishTime")
-	@WSDLDocumentation("Get the time when the run was detected as having finished.")
-	Date getRunFinishTime(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the current status of the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The status code.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Status")
-	@WSDLDocumentation("Get the current status of the given workflow run.")
-	Status getRunStatus(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Set the status of a run. This is used to start it executing, make it stop
-	 * executing, etc. Note that changing the status of a run can <i>never</i>
-	 * cause the run to be destroyed.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param status
-	 *            The status to change to. Changing to the current status will
-	 *            always have no effect.
-	 * @return An empty string if the state change was completed, or a
-	 *         description (never empty) of why the state change is ongoing.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws BadStateChangeException
-	 *             If the state change requested is impossible.
-	 */
-	@WebResult(name = "PartialityReason")
-	@WSDLDocumentation("Set the status of a given workflow run.")
-	String setRunStatus(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "status") @XmlElement(required = true) Status status)
-			throws UnknownRunException, NoUpdateException,
-			BadStateChangeException;
-
-	/**
-	 * Get the names of the event listeners attached to the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The listener names.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "ListenerName")
-	@WSDLDocumentation("Get the names of the event listeners attached to the run.")
-	String[] getRunListeners(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Adds an event listener to the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerType
-	 *            The type of event listener to add. Must be one of the names
-	 *            returned by the {@link #getServerListeners()} operation.
-	 * @param configuration
-	 *            The configuration document for the event listener; the
-	 *            interpretation of the configuration is up to the listener.
-	 * @return The actual name of the listener.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws NoListenerException
-	 *             If the listener construction fails (<i>e.g.</i>, due to an
-	 *             unsupported <b>listenerType</b> or a problem with the
-	 *             <b>configuration</b>).
-	 */
-	@WebResult(name = "ListenerName")
-	@WSDLDocumentation("Adds an event listener to the run.")
-	String addRunListener(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerType") @XmlElement(required = true) String listenerType,
-			@WebParam(name = "configuration") @XmlElement(required = true) String configuration)
-			throws UnknownRunException, NoUpdateException, NoListenerException;
-
-	/**
-	 * Returns the standard output of the workflow run. Unstarted runs return
-	 * the empty string.
-	 * <p>
-	 * The equivalent thing can also be fetched from the relevant listener
-	 * property (i.e., io/stdout).
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Whatever the run engine printed on its stdout.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "StandardOutput")
-	@WSDLDocumentation("Returns the stdout from the run engine.")
-	String getRunStdout(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Returns the standard error of the workflow run. Unstarted runs return the
-	 * empty string.
-	 * <p>
-	 * The equivalent thing can also be fetched from the relevant listener
-	 * property (i.e., io/stderr).
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Whatever the run engine printed on its stderr.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "StandardError")
-	@WSDLDocumentation("Returns the stderr from the run engine.")
-	String getRunStderr(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Returns the usage record for the workflow run. Unfinished runs return
-	 * <tt>null</tt>.
-	 * <p>
-	 * The equivalent thing can also be fetched from the relevant listener
-	 * property (i.e., io/usage).
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The usage record, or <tt>null</tt>.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "ResourceUsage")
-	@WSDLDocumentation("Returns the resource usage from the run engine.")
-	JobUsageRecord getRunUsageRecord(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Returns the log of the workflow run. Unstarted runs return the empty
-	 * string.
-	 * <p>
-	 * This can also be fetched from the appropriate file (i.e.,
-	 * <tt>logs/detail.log</tt>).
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Whatever the run engine wrote to its log.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Log")
-	@WSDLDocumentation("Returns the detailed log from the run engine.")
-	String getRunLog(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Returns the run bundle of a run. The run must be <i>finished</i> for this
-	 * to be guaranteed to be present, and must <i>not</i> have had its output
-	 * generated as Baclava.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The contents of the run bundle.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If there was a problem reading the bundle.
-	 * @throws NoDirectoryEntryException
-	 *             If the bundle doesn't exist currently.
-	 */
-	@WebResult(name = "RunBundle")
-	@WSDLDocumentation("Gets the run bundle of a finished run. MTOM support recommended!")
-	FileContents getRunBundle(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Gets whether to generate provenance (in a run bundle) for a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Whether provenance will be generated.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "GenerateProvenance")
-	@WSDLDocumentation("Gets whether a run generates provenance.")
-	boolean getRunGenerateProvenance(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Sets whether to generate provenance (in a run bundle) for a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param generateProvenance
-	 *            Whether to generate provenance.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to manipulate the run.
-	 */
-	@WSDLDocumentation("Sets whether a run generates provenance. "
-			+ "Only usefully settable before the run is started.")
-	void setRunGenerateProvenance(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "generateProvenance") @XmlElement(required = true) boolean generateProvenance)
-			throws UnknownRunException, NoUpdateException;
-
-	/**
-	 * Get the owner of the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The status code.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Owner")
-	@WSDLDocumentation("Get the owner of the given workflow run.")
-	String getRunOwner(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the list of permissions associated with a workflow run.
-	 * 
-	 * @param runName
-	 *            The name of the run whose permissions are to be obtained.
-	 * @return A description of the non-<tt>none</tt> permissions.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the current
-	 *             user is not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If asked to provide this information about a run that the
-	 *             current user may see but where they are not the owner of it.
-	 */
-	@WebResult(name = "PermissionList")
-	@WSDLDocumentation("Get the list of permissions associated with a given workflow run.")
-	PermissionList listRunPermissions(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, NotOwnerException;
-
-	/**
-	 * Set the permission for a user to access and update a particular workflow
-	 * run.
-	 * 
-	 * @param runName
-	 *            The name of the run whose permissions are to be updated.
-	 * @param userName
-	 *            The name of the user about whom this call is talking.
-	 * @param permission
-	 *            The permission level to set.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the current
-	 *             user is not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If asked to provide this information about a run that the
-	 *             current user may see but where they are not the owner of it.
-	 */
-	@WSDLDocumentation("Set the permission for a user to access and update a given workflow run.")
-	void setRunPermission(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "userName") @XmlElement(required = true) String userName,
-			@WebParam(name = "permission") @XmlElement(required = true) Permission permission)
-			throws UnknownRunException, NotOwnerException;
-
-	/**
-	 * Get the credentials associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The collection of credentials.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may see the credentials.
-	 */
-	@WebResult(name = "Credentials")
-	@WSDLDocumentation("Get the credentials (passwords, private keys) associated with the given workflow run. Only the owner may do this.")
-	Credential[] getRunCredentials(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, NotOwnerException;
-
-	/**
-	 * Set a credential associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param credentialID
-	 *            The handle of the credential to set. If empty, a new
-	 *            credential will be created.
-	 * @param credential
-	 *            The credential to set.
-	 * @return The handle of the credential that was created or updated.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may manipulate the credentials.
-	 * @throws InvalidCredentialException
-	 *             If the <b>credential</b> fails its checks.
-	 * @throws NoCredentialException
-	 *             If the <b>credentialID</b> is not empty but does not
-	 *             correspond to an existing credential.
-	 * @throws BadStateChangeException
-	 *             If an attempt to manipulate the credentials is done after the
-	 *             workflow has started running.
-	 */
-	@WebResult(name = "credentialID")
-	@WSDLDocumentation("Set a credential (password, private key, etc.) associated with the given run. Only the owner may do this.")
-	String setRunCredential(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "credentialID") @XmlElement(required = true) String credentialID,
-			@WebParam(name = "credential") @XmlElement(required = true) Credential credential)
-			throws UnknownRunException, NotOwnerException,
-			InvalidCredentialException, NoCredentialException,
-			BadStateChangeException;
-
-	/**
-	 * Delete a credential associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param credentialID
-	 *            The handle of the credential to delete. If empty, a new
-	 *            credential will be created.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may manipulate the credentials.
-	 * @throws NoCredentialException
-	 *             If the given credentialID does not exist.
-	 * @throws BadStateChangeException
-	 *             If an attempt to manipulate the credentials is done after the
-	 *             workflow has started running.
-	 */
-	@WSDLDocumentation("Delete a credential associated with the given run. Only the owner may do this.")
-	void deleteRunCredential(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "credentialID") @XmlElement(required = true) String credentialID)
-			throws UnknownRunException, NotOwnerException,
-			NoCredentialException, BadStateChangeException;
-
-	/**
-	 * Get the certificate collections associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The collection of credentials.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may see the credentials.
-	 */
-	@WebResult(name = "CertificateCollections")
-	@WSDLDocumentation("Get the trusted (server or CA) certificates associated with the run. Only the owner may do this.")
-	Trust[] getRunCertificates(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, NotOwnerException;
-
-	/**
-	 * Set a certificate collection associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param certificateID
-	 *            The handle of the certificate collection to set. If empty, a
-	 *            new certificate collection will be created.
-	 * @param certificate
-	 *            The certificate collection to set.
-	 * @return The handle of the certificate set that was created or updated.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may manipulate the certificates.
-	 * @throws InvalidCredentialException
-	 *             If the <b>certificate</b> fails its checks.
-	 * @throws NoCredentialException
-	 *             If the <b>credentialID</b> is not empty but does not
-	 *             correspond to an existing certificate collection.
-	 * @throws BadStateChangeException
-	 *             If an attempt to manipulate the credentials is done after the
-	 *             workflow has started running.
-	 */
-	@WebResult(name = "certificateID")
-	@WSDLDocumentation("Set a trusted (server or CA) certificate associated with the run. Only the owner may do this.")
-	String setRunCertificates(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "certificateID") String certificateID,
-			@WebParam(name = "certificate") @XmlElement(required = true) Trust certificate)
-			throws UnknownRunException, NotOwnerException,
-			InvalidCredentialException, NoCredentialException,
-			BadStateChangeException;
-
-	/**
-	 * Delete a certificate collection associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param certificateID
-	 *            The handle of the credential to delete.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may manipulate the certificates.
-	 * @throws NoCredentialException
-	 *             If the given certificateID does not exist.
-	 * @throws BadStateChangeException
-	 *             If an attempt to manipulate the credentials is done after the
-	 *             workflow has started running.
-	 */
-	@WSDLDocumentation("Delete a trusted (server or CA) certificate associated with the run. Only the owner may do this.")
-	void deleteRunCertificates(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "certificateID") @XmlElement(required = true) String certificateID)
-			throws UnknownRunException, NotOwnerException,
-			NoCredentialException, BadStateChangeException;
-
-	/**
-	 * Get the contents of any directory at/under the run's working directory.
-	 * Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param directory
-	 *            The name of the directory to fetch; the main working directory
-	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return A list of entries. They are assumed to be all directories or
-	 *         files.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a file).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the directory can't be looked up.
-	 */
-	@WebResult(name = "DirectoryEntry")
-	@WSDLDocumentation("Get the contents of any directory at/under the run's working directory.")
-	DirEntry[] getRunDirectoryContents(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the contents of any directory (and its subdirectories) at/under the
-	 * run's working directory, returning it as a compressed ZIP file. Runs do
-	 * not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param directory
-	 *            The name of the directory to fetch; the main working directory
-	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return A serialized ZIP file.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a file).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the directory can't be looked up.
-	 */
-	@WebResult(name = "ZipFile")
-	@WSDLDocumentation("Get the contents of any directory (and its subdirectories) at/under the run's working directory, returning it as a compressed ZIP file.")
-	byte[] getRunDirectoryAsZip(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the contents of any directory (and its subdirectories) at/under the
-	 * run's working directory, returning it as a compressed ZIP file that is
-	 * streamed via MTOM. Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param directory
-	 *            The name of the directory to fetch; the main working directory
-	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return An MTOM-streamable ZIP file reference.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a file).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the directory can't be looked up.
-	 */
-	@WebResult(name = "ZipStream")
-	@WSDLDocumentation("Get the contents of any directory (and its subdirectories) at/under the run's working directory, returning it as a compressed ZIP file that is streamed by MTOM.")
-	ZippedDirectory getRunDirectoryAsZipMTOM(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Make a new empty directory beneath an existing one, which must be the
-	 * run's working directory or a directory beneath it. Runs do not share
-	 * working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param parent
-	 *            The parent directory that will have the new directory added
-	 *            beneath it.
-	 * @param name
-	 *            The name of the directory to create. Must not be the same as
-	 *            any other file or directory in the <i>parent</i> directory.
-	 *            The name <i>must not</i> consist of <tt>..</tt> or have a
-	 *            <tt>/</tt> in it.
-	 * @return A reference to the created directory.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., making something with
-	 *             the same name as something that already exists).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the containing directory can't be looked up.
-	 */
-	@WebResult(name = "CreatedDirectory")
-	@WSDLDocumentation("Make a new empty directory beneath an existing one, all relative to the given run's main working directory.")
-	DirEntry makeRunDirectory(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "parentDirectory") @XmlElement(required = true) DirEntry parent,
-			@WebParam(name = "directoryName") @XmlElement(required = true) String name)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Make a new empty file in an existing directory, which may be the run's
-	 * working directory or any directory beneath it. Runs do not share working
-	 * directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param parent
-	 *            The parent directory that will have the new file added to it.
-	 * @param name
-	 *            The name of the file to create. Must not be the same as any
-	 *            other file or directory in the <i>parent</i> directory. The
-	 *            name <i>must not</i> consist of <tt>..</tt> or have a
-	 *            <tt>/</tt> in it.
-	 * @return A reference to the created file. The file will be empty.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., making something with
-	 *             the same name as something that already exists).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the containing directory can't be looked up.
-	 */
-	@WebResult(name = "CreatedFile")
-	@WSDLDocumentation("Make a new empty file in an existing directory, which may be the run's working directory or any directory beneath it.")
-	DirEntry makeRunFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "parentDirectory") @XmlElement(required = true) DirEntry parent,
-			@WebParam(name = "fileNameTail") @XmlElement(required = true) String name)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Destroy an entry (file or directory) in or beneath a run's working
-	 * directory. Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param dirEntry
-	 *            Reference to an existing item in a directory that will be
-	 *            destroyed. May be a reference to either a file or a directory.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., deleting something
-	 *             which doesn't exist or attempting to delete the main working
-	 *             directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the file or directory can't be looked up.
-	 */
-	@WSDLDocumentation("Destroy an entry (file or directory) in or beneath a run's working directory.")
-	void destroyRunDirectoryEntry(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "directoryEntry") @XmlElement(required = true) DirEntry dirEntry)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Get the contents of a file under the run's working directory. Runs do not
-	 * share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to fetch; the main working directory is
-	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return The literal byte contents of the file.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WebResult(name = "FileContents")
-	@WSDLDocumentation("Get the contents of a file under the run's working directory.")
-	byte[] getRunFileContents(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the contents of a file under the run's working directory via MTOM.
-	 * Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to fetch; the main working directory is
-	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return The contents, described for transfer via MTOM.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WebResult(name = "FileContentsMTOM")
-	@WSDLDocumentation("Get the contents of a file via MTOM.")
-	FileContents getRunFileContentsMTOM(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Set the contents of a file under the run's working directory. Runs do not
-	 * share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to update; the main working directory is
-	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @param newContents
-	 *            The literal bytes to set the file contents to.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., writing the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WSDLDocumentation("Set the contents of a file under the run's working directory.")
-	void setRunFileContents(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file,
-			@WebParam(name = "contents") @XmlElement(required = true) byte[] newContents)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Set the contents of a file under the run's working directory. Runs do not
-	 * share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param newContents
-	 *            The description of what file to set, and what to the file
-	 *            contents should be set to.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., writing the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WSDLDocumentation("Set the contents of a file under the run's working directory.")
-	void setRunFileContentsMTOM(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "contents") @XmlElement(required = true) FileContents newContents)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Set the contents of a file under the run's working directory to the
-	 * contents of a publicly readable URI. Runs do not share working
-	 * directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to update; the main working directory is
-	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @param reference
-	 *            The publicly readable URI whose contents are to become the
-	 *            literal bytes of the file's contents.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., writing the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WSDLDocumentation("Set the contents of a file under the run's working directory from the contents of a publicly readable URI.")
-	void setRunFileContentsFromURI(@WebParam(name = "runName") String runName,
-			@WebParam(name = "fileName") DirEntryReference file,
-			@WebParam(name = "contents") URI reference)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Get the length of any file (in bytes) at/under the run's working
-	 * directory. Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to get the length of; the main working
-	 *            directory is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return The number of bytes in the file.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the length of a
-	 *             directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WebResult(name = "FileLength")
-	@WSDLDocumentation("Get the length of any file (in bytes) at/under the run's working directory.")
-	long getRunFileLength(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the time that the file or directory (at/under the run's working
-	 * directory) was last modified. Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to get the modification date of; the main
-	 *            working directory is <tt>/</tt> and <tt>..</tt> is always
-	 *            disallowed.
-	 * @return The modification date of the file or directory, as understood by
-	 *         the underlying operating system.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated.
-	 * @throws NoDirectoryEntryException
-	 *             If the file or directory doesn't exist.
-	 */
-	@WebResult(name = "FileModified")
-	@WSDLDocumentation("Get the length of any file (in bytes) at/under the run's working directory.")
-	Date getRunFileModified(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the content type of any file at/under the run's working directory.
-	 * Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to get the length of; the main working
-	 *            directory is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return The content type of the file.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the length of a
-	 *             directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WebResult(name = "FileContentType")
-	@WSDLDocumentation("Get the content type of any file at/under the run's working directory.")
-	String getRunFileType(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the configuration document for an event listener attached to a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerName
-	 *            The name of the listener attached.
-	 * @return The configuration document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoListenerException
-	 *             If no such listener exists.
-	 */
-	@WebResult(name = "ListenerConfiguration")
-	@WSDLDocumentation("Get the configuration document for an event listener attached to a run.")
-	String getRunListenerConfiguration(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName)
-			throws UnknownRunException, NoListenerException;
-
-	/**
-	 * Get the list of properties supported by an event listener attached to a
-	 * run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerName
-	 *            The name of the listener attached.
-	 * @return The list of property names.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoListenerException
-	 *             If no such listener exists.
-	 */
-	@WebResult(name = "ListenerPropertyName")
-	@WSDLDocumentation("Get the list of properties supported by an event listener attached to a run.")
-	String[] getRunListenerProperties(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName)
-			throws UnknownRunException, NoListenerException;
-
-	/**
-	 * Get the value of a property for an event listener attached to a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerName
-	 *            The name of the listener attached.
-	 * @param propertyName
-	 *            The name of the property to read.
-	 * @return The configuration document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoListenerException
-	 *             If no such listener exists or if the listener has no such
-	 *             property.
-	 */
-	@WebResult(name = "ListenerPropertyValue")
-	@WSDLDocumentation("Get the value of a property for an event listener attached to a run.")
-	String getRunListenerProperty(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName,
-			@WebParam(name = "propertyName") @XmlElement(required = true) String propertyName)
-			throws UnknownRunException, NoListenerException;
-
-	/**
-	 * Set the value of a property for an event listener attached to a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerName
-	 *            The name of the listener attached.
-	 * @param propertyName
-	 *            The name of the property to write.
-	 * @param value
-	 *            The value to set the property to.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoListenerException
-	 *             If no such listener exists, the listener has no such
-	 *             property, or the value is considered "unacceptable" in some
-	 *             way.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 */
-	@WSDLDocumentation("Set the value of a property for an event listener attached to a run.")
-	void setRunListenerProperty(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName,
-			@WebParam(name = "propertyName") @XmlElement(required = true) String propertyName,
-			@WebParam(name = "propertyValue") @XmlElement(required = true) String value)
-			throws UnknownRunException, NoUpdateException, NoListenerException;
-
-	/**
-	 * Gets the status of the server. Follows the HELIO Monitoring Service
-	 * protocol.
-	 * 
-	 * @return A status string.
-	 */
-	@WSDLDocumentation("A simple way to get the status of the overall server.")
-	@WebResult(name = "ServerStatus")
-	String getServerStatus();
-}


[34/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/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
deleted file mode 100644
index bc91f0e..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index fc4baff..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index e2519f8..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 89a7cff..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-/**
- * 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/00397eff/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
deleted file mode 100644
index a7af96b..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */
-
-/**
- * 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/00397eff/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
deleted file mode 100644
index 6466e2f..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- */
-/**
- * Interfaces exported by worker classes to the server.
- */
-package org.taverna.server.localworker.remote;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/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
deleted file mode 100644
index cc0127e..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- */
-package org.taverna.server.localworker.server;
-/*
- * 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.
- */
-
-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/00397eff/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
deleted file mode 100644
index 584f1ed..0000000
--- a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- */
-/**
- * Interfaces exported by the server to worker classes.
- */
-package org.taverna.server.localworker.server;
-/*
- * 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.
- */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-unix-forker/src/main/java/org/apache/taverna/server/unixforker/Forker.java
----------------------------------------------------------------------
diff --git a/taverna-server-unix-forker/src/main/java/org/apache/taverna/server/unixforker/Forker.java b/taverna-server-unix-forker/src/main/java/org/apache/taverna/server/unixforker/Forker.java
new file mode 100644
index 0000000..ebe73f4
--- /dev/null
+++ b/taverna-server-unix-forker/src/main/java/org/apache/taverna/server/unixforker/Forker.java
@@ -0,0 +1,221 @@
+/*
+ */
+package org.taverna.server.unixforker;
+/*
+ * 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.
+ */
+
+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/00397eff/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
deleted file mode 100644
index ebe73f4..0000000
--- a/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- */
-package org.taverna.server.unixforker;
-/*
- * 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.
- */
-
-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/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ContentsDescriptorBuilder.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ContentsDescriptorBuilder.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ContentsDescriptorBuilder.java
new file mode 100644
index 0000000..051a037
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ContentsDescriptorBuilder.java
@@ -0,0 +1,305 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static eu.medsea.util.MimeUtil.getMimeType;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.common.Uri.secure;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.port_description.AbsentValue;
+import org.taverna.server.port_description.AbstractPortDescription;
+import org.taverna.server.port_description.AbstractValue;
+import org.taverna.server.port_description.ErrorValue;
+import org.taverna.server.port_description.InputDescription;
+import org.taverna.server.port_description.InputDescription.InputPort;
+import org.taverna.server.port_description.LeafValue;
+import org.taverna.server.port_description.ListValue;
+import org.taverna.server.port_description.OutputDescription;
+import org.taverna.server.port_description.OutputDescription.OutputPort;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.OutputWorkflowPort;
+
+/**
+ * A class that is used to build descriptions of the contents of a workflow
+ * run's filesystem.
+ * 
+ * @author Donal Fellows
+ */
+public class ContentsDescriptorBuilder {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private FilenameUtils fileUtils;
+	private UriBuilderFactory uriBuilderFactory;
+
+	@Required
+	public void setUriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
+		this.uriBuilderFactory = uriBuilderFactory;
+	}
+
+	@Required
+	public void setFileUtils(FilenameUtils fileUtils) {
+		this.fileUtils = fileUtils;
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	private Workflow fillInFromWorkflow(TavernaRun run, UriBuilder ub,
+			AbstractPortDescription portDesc) throws IOException {
+		WorkflowBundle bundle = run.getWorkflow().getScufl2Workflow();
+		bundle.getMainWorkflow().getInputPorts();
+		portDesc.fillInBaseData(bundle.getMainWorkflow()
+				.getIdentifier().toString(), run.getId(), ub.build());
+		return bundle.getMainWorkflow();
+	}
+
+	/**
+	 * Computes the depth of value in a descriptor.
+	 * 
+	 * @param value
+	 *            The value description to characterise.
+	 * @return Its depth (i.e., the depth of the port outputting the value) or
+	 *         <tt>null</tt> if that is impossible to determine.
+	 */
+	private Integer computeDepth(AbstractValue value) {
+		if (value instanceof ListValue) {
+			int mv = 1;
+			for (AbstractValue v : ((ListValue) value).contents) {
+				Integer d = computeDepth(v);
+				if (d != null && mv <= d)
+					mv = d + 1;
+			}
+			return mv;
+		} else if (value instanceof LeafValue || value instanceof ErrorValue)
+			return 0;
+		else
+			return null;
+	}
+
+	/**
+	 * Build a description of a leaf value.
+	 * 
+	 * @param file
+	 *            The file representing the value.
+	 * @return A value descriptor.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	private LeafValue constructLeafValue(File file)
+			throws FilesystemAccessException {
+		LeafValue v = new LeafValue();
+		v.fileName = file.getFullName();
+		v.byteLength = file.getSize();
+		try {
+			byte[] head = file.getContents(0, 1024);
+			v.contentType = getMimeType(new ByteArrayInputStream(head));
+		} catch (Exception e) {
+			v.contentType = APPLICATION_OCTET_STREAM_TYPE.toString();
+		}
+		return v;
+	}
+
+	/**
+	 * Build a description of an error value.
+	 * 
+	 * @param file
+	 *            The file representing the error.
+	 * @return A value descriptor.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	private ErrorValue constructErrorValue(File file)
+			throws FilesystemAccessException {
+		ErrorValue v = new ErrorValue();
+		v.fileName = file.getFullName();
+		v.byteLength = file.getSize();
+		return v;
+	}
+
+	/**
+	 * Build a description of a list value.
+	 * 
+	 * @param dir
+	 *            The directory representing the list.
+	 * @param ub
+	 *            The factory for URIs.
+	 * @return A value descriptor.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	private ListValue constructListValue(Directory dir, UriBuilder ub)
+			throws FilesystemAccessException {
+		ListValue v = new ListValue();
+		v.length = 0;
+		Set<DirectoryEntry> contents = new HashSet<>(dir.getContents());
+		Iterator<DirectoryEntry> it = contents.iterator();
+		while (it.hasNext())
+			if (!it.next().getName().matches("^[0-9]+([.].*)?$"))
+				it.remove();
+		for (int i = 1; !contents.isEmpty(); i++) {
+			String exact = Integer.toString(i);
+			AbstractValue subval = constructValue(contents, ub, exact);
+			v.contents.add(subval);
+			if (!(subval instanceof AbsentValue)) {
+				v.length = i;
+				String pfx = i + ".";
+				for (DirectoryEntry de : contents)
+					if (de.getName().equals(exact)
+							|| de.getName().startsWith(pfx)) {
+						contents.remove(de);
+						break;
+					}
+			}
+		}
+		return v;
+	}
+
+	/**
+	 * Build a value description.
+	 * 
+	 * @param parentContents
+	 *            The contents of the parent directory.
+	 * @param ub
+	 *            The factory for URIs.
+	 * @param name
+	 *            The name of the value's file/directory representative.
+	 * @return A value descriptor.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	private AbstractValue constructValue(
+			Collection<DirectoryEntry> parentContents, UriBuilder ub,
+			String name) throws FilesystemAccessException {
+		String error = name + ".error";
+		String prefix = name + ".";
+		for (DirectoryEntry entry : parentContents) {
+			AbstractValue av;
+			if (entry.getName().equals(error) && entry instanceof File) {
+				av = constructErrorValue((File) entry);
+			} else if (!entry.getName().equals(name)
+					&& !entry.getName().startsWith(prefix))
+				continue;
+			else if (entry instanceof File)
+				av = constructLeafValue((File) entry);
+			else
+				av = constructListValue((Directory) entry, ub);
+			String fullPath = entry.getFullName().replaceFirst("^/", "");
+			av.href = ub.clone().path(fullPath).build();
+			return av;
+		}
+		return new AbsentValue();
+	}
+
+	/**
+	 * Construct a description of the outputs of a workflow run.
+	 * 
+	 * @param run
+	 *            The workflow run whose outputs are to be described.
+	 * @param ui
+	 *            The origin for URIs.
+	 * @return The description, which can be serialized to XML.
+	 * @throws FilesystemAccessException
+	 *             If something goes wrong reading the directories.
+	 * @throws NoDirectoryEntryException
+	 *             If something goes wrong reading the directories.
+	 */
+	public OutputDescription makeOutputDescriptor(TavernaRun run, UriInfo ui)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		OutputDescription descriptor = new OutputDescription();
+		try {
+			UriBuilder ub = getRunUriBuilder(run, ui);
+			Workflow dataflow = fillInFromWorkflow(run, ub, descriptor);
+			Collection<DirectoryEntry> outs = null;
+			ub = ub.path("wd/{path}");
+			for (OutputWorkflowPort output : dataflow.getOutputPorts()) {
+				OutputPort p = descriptor.addPort(output.getName());
+				if (run.getOutputBaclavaFile() == null) {
+					if (outs == null)
+						outs = fileUtils.getDirectory(run, "out").getContents();
+					p.output = constructValue(outs, ub, p.name);
+					p.depth = computeDepth(p.output);
+				}
+			}
+		} catch (IOException e) {
+			log.info("failure in conversion to .scufl2", e);
+		}
+		return descriptor;
+	}
+
+	private UriBuilder getRunUriBuilder(TavernaRun run, UriInfo ui) {
+		if (ui == null)
+			return secure(uriBuilderFactory.getRunUriBuilder(run));
+		else
+			return secure(fromUri(ui.getAbsolutePath().toString()
+					.replaceAll("/(out|in)put/?$", "")));
+	}
+
+	/**
+	 * Constructs input descriptions.
+	 * 
+	 * @param run
+	 *            The run to build for.
+	 * @param ui
+	 *            The mechanism for building URIs.
+	 * @return The description of the <i>expected</i> inputs of the run.
+	 */
+	public InputDescription makeInputDescriptor(TavernaRun run, UriInfo ui) {
+		InputDescription desc = new InputDescription();
+		try {
+			UriBuilder ub = getRunUriBuilder(run, ui);
+			Workflow workflow = fillInFromWorkflow(run, ub, desc);
+			ub = ub.path("input/{name}");
+			for (InputWorkflowPort port : workflow.getInputPorts()) {
+				InputPort in = desc.addPort(port.getName());
+				in.href = ub.build(in.name);
+				try {
+					in.depth = port.getDepth();
+				} catch (NumberFormatException ex) {
+					in.depth = null;
+				}
+			}
+		} catch (IOException e) {
+			log.info("failure in conversion to .scufl2", e);
+		}
+		return desc;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/DirectoryREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/DirectoryREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/DirectoryREST.java
new file mode 100644
index 0000000..b800c1c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/DirectoryREST.java
@@ -0,0 +1,388 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.Response.noContent;
+import static javax.ws.rs.core.Response.ok;
+import static javax.ws.rs.core.Response.seeOther;
+import static javax.ws.rs.core.Response.status;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
+import static org.taverna.server.master.api.ContentTypes.DIRECTORY_VARIANTS;
+import static org.taverna.server.master.api.ContentTypes.INITIAL_FILE_VARIANTS;
+import static org.taverna.server.master.common.Roles.SELF;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.PathSegment;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.Variant;
+import javax.xml.ws.Holder;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.DirectoryBean;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.DirectoryContents;
+import org.taverna.server.master.rest.FileSegment;
+import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
+import org.taverna.server.master.rest.MakeOrUpdateDirEntry.MakeDirectory;
+import org.taverna.server.master.rest.TavernaServerDirectoryREST;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful access to the filesystem.
+ * 
+ * @author Donal Fellows
+ */
+class DirectoryREST implements TavernaServerDirectoryREST, DirectoryBean {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private TavernaServerSupport support;
+	private TavernaRun run;
+	private FilenameUtils fileUtils;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	@Required
+	public void setFileUtils(FilenameUtils fileUtils) {
+		this.fileUtils = fileUtils;
+	}
+
+	@Override
+	public DirectoryREST connect(TavernaRun run) {
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response destroyDirectoryEntry(List<PathSegment> path)
+			throws NoUpdateException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		support.permitUpdate(run);
+		fileUtils.getDirEntry(run, path).destroy();
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public DirectoryContents getDescription(UriInfo ui)
+			throws FilesystemAccessException {
+		return new DirectoryContents(ui, run.getWorkingDirectory()
+				.getContents());
+	}
+
+	@Override
+	@CallCounted
+	public Response options(List<PathSegment> path) {
+		return opt("PUT", "POST", "DELETE");
+	}
+
+	/*
+	 * // Nasty! This can have several different responses...
+	 * 
+	 * @Override @CallCounted private Response
+	 * getDirectoryOrFileContents(List<PathSegment> path, UriInfo ui, Request
+	 * req) throws FilesystemAccessException, NoDirectoryEntryException {
+	 * 
+	 * DirectoryEntry de = fileUtils.getDirEntry(run, path);
+	 * 
+	 * // How did the user want the result?
+	 * 
+	 * List<Variant> variants = getVariants(de); Variant v =
+	 * req.selectVariant(variants); if (v == null) return
+	 * notAcceptable(variants).type(TEXT_PLAIN)
+	 * .entity("Do not know what type of response to produce.") .build();
+	 * 
+	 * // Produce the content to deliver up
+	 * 
+	 * Object result; if
+	 * (v.getMediaType().equals(APPLICATION_OCTET_STREAM_TYPE))
+	 * 
+	 * // Only for files...
+	 * 
+	 * result = de; else if (v.getMediaType().equals(APPLICATION_ZIP_TYPE))
+	 * 
+	 * // Only for directories...
+	 * 
+	 * result = ((Directory) de).getContentsAsZip(); else
+	 * 
+	 * // Only for directories... // XML or JSON; let CXF pick what to do
+	 * 
+	 * result = new DirectoryContents(ui, ((Directory) de).getContents());
+	 * return ok(result).type(v.getMediaType()).build();
+	 * 
+	 * }
+	 */
+
+	private boolean matchType(MediaType a, MediaType b) {
+		if (log.isDebugEnabled())
+			log.debug("comparing " + a.getType() + "/" + a.getSubtype()
+					+ " and " + b.getType() + "/" + b.getSubtype());
+		return (a.isWildcardType() || b.isWildcardType() || a.getType().equals(
+				b.getType()))
+				&& (a.isWildcardSubtype() || b.isWildcardSubtype() || a
+						.getSubtype().equals(b.getSubtype()));
+	}
+
+	/**
+	 * What are we willing to serve up a directory or file as?
+	 * 
+	 * @param de
+	 *            The reference to the object to serve.
+	 * @return The variants we can serve it as.
+	 * @throws FilesystemAccessException
+	 *             If we fail to read data necessary to detection of its media
+	 *             type.
+	 */
+	private List<Variant> getVariants(DirectoryEntry de)
+			throws FilesystemAccessException {
+		if (de instanceof Directory)
+			return DIRECTORY_VARIANTS;
+		else if (!(de instanceof File))
+			throw new FilesystemAccessException("not a directory or file!");
+		File f = (File) de;
+		List<Variant> variants = new ArrayList<>(INITIAL_FILE_VARIANTS);
+		String contentType = support.getEstimatedContentType(f);
+		if (!contentType.equals(APPLICATION_OCTET_STREAM)) {
+			String[] ct = contentType.split("/");
+			variants.add(0,
+					new Variant(new MediaType(ct[0], ct[1]), (String) null, null));
+		}
+		return variants;
+	}
+
+	/** How did the user want the result? */
+	private MediaType pickType(HttpHeaders headers, DirectoryEntry de)
+			throws FilesystemAccessException, NegotiationFailedException {
+		List<Variant> variants = getVariants(de);
+		// Manual content negotiation!!! Ugh!
+		for (MediaType mt : headers.getAcceptableMediaTypes())
+			for (Variant v : variants)
+				if (matchType(mt, v.getMediaType()))
+					return v.getMediaType();
+		throw new NegotiationFailedException(
+				"Do not know what type of response to produce.", variants);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response getDirectoryOrFileContents(List<PathSegment> path,
+			UriInfo ui, HttpHeaders headers) throws FilesystemAccessException,
+			NoDirectoryEntryException, NegotiationFailedException {
+		DirectoryEntry de = fileUtils.getDirEntry(run, path);
+
+		// How did the user want the result?
+		MediaType wanted = pickType(headers, de);
+
+		log.info("producing content of type " + wanted);
+		// Produce the content to deliver up
+		Object result;
+		if (de instanceof File) {
+			// Only for files...
+			result = de;
+			List<String> range = headers.getRequestHeader("Range");
+			if (range != null && range.size() == 1)
+				return new FileSegment((File) de, range.get(0))
+						.toResponse(wanted);
+		} else {
+			// Only for directories...
+			Directory d = (Directory) de;
+			if (wanted.getType().equals(APPLICATION_ZIP_TYPE.getType())
+					&& wanted.getSubtype().equals(
+							APPLICATION_ZIP_TYPE.getSubtype()))
+				result = d.getContentsAsZip();
+			else
+				// XML or JSON; let CXF pick what to do
+				result = new DirectoryContents(ui, d.getContents());
+		}
+		return ok(result).type(wanted).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response makeDirectoryOrUpdateFile(List<PathSegment> parent,
+			MakeOrUpdateDirEntry op, UriInfo ui) throws NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException {
+		support.permitUpdate(run);
+		DirectoryEntry container = fileUtils.getDirEntry(run, parent);
+		if (!(container instanceof Directory))
+			throw new FilesystemAccessException("You may not "
+					+ ((op instanceof MakeDirectory) ? "make a subdirectory of"
+							: "place a file in") + " a file.");
+		if (op.name == null || op.name.length() == 0)
+			throw new FilesystemAccessException("missing name attribute");
+		Directory d = (Directory) container;
+		UriBuilder ub = secure(ui).path("{name}");
+
+		// Make a directory in the context directory
+
+		if (op instanceof MakeDirectory) {
+			Directory target = d.makeSubdirectory(support.getPrincipal(),
+					op.name);
+			return created(ub.build(target.getName())).build();
+		}
+
+		// Make or set the contents of a file
+
+		File f = null;
+		for (DirectoryEntry e : d.getContents()) {
+			if (e.getName().equals(op.name)) {
+				if (e instanceof Directory)
+					throw new FilesystemAccessException(
+							"You may not overwrite a directory with a file.");
+				f = (File) e;
+				break;
+			}
+		}
+		if (f == null) {
+			f = d.makeEmptyFile(support.getPrincipal(), op.name);
+			f.setContents(op.contents);
+			return created(ub.build(f.getName())).build();
+		}
+		f.setContents(op.contents);
+		return seeOther(ub.build(f.getName())).build();
+	}
+
+	private File getFileForWrite(List<PathSegment> filePath,
+			Holder<Boolean> isNew) throws FilesystemAccessException,
+			NoDirectoryEntryException, NoUpdateException {
+		support.permitUpdate(run);
+		if (filePath == null || filePath.size() == 0)
+			throw new FilesystemAccessException(
+					"Cannot create a file that is not in a directory.");
+
+		List<PathSegment> dirPath = new ArrayList<>(filePath);
+		String name = dirPath.remove(dirPath.size() - 1).getPath();
+		DirectoryEntry de = fileUtils.getDirEntry(run, dirPath);
+		if (!(de instanceof Directory)) {
+			throw new FilesystemAccessException(
+					"Cannot create a file that is not in a directory.");
+		}
+		Directory d = (Directory) de;
+
+		File f = null;
+		isNew.value = false;
+		for (DirectoryEntry e : d.getContents())
+			if (e.getName().equals(name)) {
+				if (e instanceof File) {
+					f = (File) e;
+					break;
+				}
+				throw new FilesystemAccessException(
+						"Cannot create a file that is not in a directory.");
+			}
+
+		if (f == null) {
+			f = d.makeEmptyFile(support.getPrincipal(), name);
+			isNew.value = true;
+		} else
+			f.setContents(new byte[0]);
+		return f;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response setFileContents(List<PathSegment> filePath,
+			InputStream contents, UriInfo ui) throws NoDirectoryEntryException,
+			NoUpdateException, FilesystemAccessException {
+		Holder<Boolean> isNew = new Holder<>(true);
+		support.copyStreamToFile(contents, getFileForWrite(filePath, isNew));
+
+		if (isNew.value)
+			return created(ui.getAbsolutePath()).build();
+		else
+			return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response setFileContentsFromURL(List<PathSegment> filePath,
+			List<URI> referenceList, UriInfo ui)
+			throws NoDirectoryEntryException, NoUpdateException,
+			FilesystemAccessException {
+		support.permitUpdate(run);
+		if (referenceList.isEmpty() || referenceList.size() > 1)
+			return status(422).entity("URI list must have single URI in it")
+					.build();
+		URI uri = referenceList.get(0);
+		try {
+			uri.toURL();
+		} catch (MalformedURLException e) {
+			return status(422).entity("URI list must have value URL in it")
+					.build();
+		}
+		Holder<Boolean> isNew = new Holder<>(true);
+		File f = getFileForWrite(filePath, isNew);
+
+		try {
+			support.copyDataToFile(uri, f);
+		} catch (MalformedURLException ex) {
+			// Should not happen; called uri.toURL() successfully above
+			throw new NoUpdateException("failed to parse URI", ex);
+		} catch (IOException ex) {
+			throw new FilesystemAccessException(
+					"failed to transfer data from URI", ex);
+		}
+
+		if (isNew.value)
+			return created(ui.getAbsolutePath()).build();
+		else
+			return noContent().build();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/FileConcatenation.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/FileConcatenation.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/FileConcatenation.java
new file mode 100644
index 0000000..4ccb033
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/FileConcatenation.java
@@ -0,0 +1,84 @@
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * Simple concatenation of files.
+ * 
+ * @author Donal Fellows
+ */
+public class FileConcatenation implements Iterable<File> {
+	private List<File> files = new ArrayList<>();
+
+	public void add(File f) {
+		files.add(f);
+	}
+
+	public boolean isEmpty() {
+		return files.isEmpty();
+	}
+
+	/**
+	 * @return The total length of the files, or -1 if this cannot be
+	 *         determined.
+	 */
+	public long size() {
+		long size = 0;
+		for (File f : files)
+			try {
+				size += f.getSize();
+			} catch (FilesystemAccessException e) {
+				// Ignore; shouldn't happen but can't guarantee
+			}
+		return (size == 0 && !files.isEmpty() ? -1 : size);
+	}
+
+	/**
+	 * Get the concatenated files.
+	 * 
+	 * @param encoding
+	 *            The encoding to use.
+	 * @return The concatenated files.
+	 * @throws UnsupportedEncodingException
+	 *             If the encoding doesn't exist.
+	 */
+	public String get(String encoding) throws UnsupportedEncodingException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		for (File f : files)
+			try {
+				baos.write(f.getContents(0, -1));
+			} catch (FilesystemAccessException | IOException e) {
+				continue;
+			}
+		return baos.toString(encoding);
+	}
+
+	@Override
+	public Iterator<File> iterator() {
+		return files.iterator();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InputREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InputREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InputREST.java
new file mode 100644
index 0000000..b9c8f55
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InputREST.java
@@ -0,0 +1,265 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.util.Date;
+
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.cxf.jaxrs.impl.MetadataMap;
+import org.apache.cxf.jaxrs.model.URITemplate;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.InputBean;
+import org.taverna.server.master.common.DirEntryReference;
+import org.taverna.server.master.exceptions.BadInputPortNameException;
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.Input;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerInputREST;
+import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.AbstractContents;
+import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.Reference;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.taverna.server.port_description.InputDescription;
+
+/**
+ * RESTful interface to the input descriptor of a single workflow run.
+ * 
+ * @author Donal Fellows
+ */
+class InputREST implements TavernaServerInputREST, InputBean {
+	private UriInfo ui;
+	private TavernaServerSupport support;
+	private TavernaRun run;
+	private ContentsDescriptorBuilder cdBuilder;
+	private FilenameUtils fileUtils;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	@Required
+	public void setCdBuilder(ContentsDescriptorBuilder cdBuilder) {
+		this.cdBuilder = cdBuilder;
+	}
+
+	@Override
+	@Required
+	public void setFileUtils(FilenameUtils fileUtils) {
+		this.fileUtils = fileUtils;
+	}
+
+	@Override
+	public InputREST connect(TavernaRun run, UriInfo ui) {
+		this.run = run;
+		this.ui = ui;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public InputsDescriptor get() {
+		return new InputsDescriptor(ui, run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public InputDescription getExpected() {
+		return cdBuilder.makeInputDescriptor(run, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String getBaclavaFile() {
+		String i = run.getInputBaclavaFile();
+		return i == null ? "" : i;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public InDesc getInput(String name, UriInfo ui) throws BadInputPortNameException {
+		Input i = support.getInput(run, name);
+		if (i == null)
+			throw new BadInputPortNameException("unknown input port name");
+		return new InDesc(i, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String setBaclavaFile(String filename) throws NoUpdateException,
+			BadStateChangeException, FilesystemAccessException {
+		support.permitUpdate(run);
+		run.setInputBaclavaFile(filename);
+		String i = run.getInputBaclavaFile();
+		return i == null ? "" : i;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public InDesc setInput(String name, InDesc inputDescriptor, UriInfo ui)
+			throws NoUpdateException, BadStateChangeException,
+			FilesystemAccessException, BadInputPortNameException,
+			BadPropertyValueException {
+		inputDescriptor.descriptorRef = null;
+		AbstractContents ac = inputDescriptor.assignment;
+		if (name == null || name.isEmpty())
+			throw new BadInputPortNameException("bad input name");
+		if (ac == null)
+			throw new BadPropertyValueException("no content!");
+		if (inputDescriptor.delimiter != null
+				&& inputDescriptor.delimiter.isEmpty())
+			inputDescriptor.delimiter = null;
+		if (ac instanceof InDesc.Reference)
+			return setRemoteInput(name, (InDesc.Reference) ac,
+					inputDescriptor.delimiter, ui);
+		if (!(ac instanceof InDesc.File || ac instanceof InDesc.Value))
+			throw new BadPropertyValueException("unknown content type");
+		support.permitUpdate(run);
+		Input i = support.getInput(run, name);
+		if (i == null)
+			i = run.makeInput(name);
+		if (ac instanceof InDesc.File)
+			i.setFile(ac.contents);
+		else
+			i.setValue(ac.contents);
+		i.setDelimiter(inputDescriptor.delimiter);
+		return new InDesc(i, ui);
+	}
+
+	private InDesc setRemoteInput(String name, Reference ref, String delimiter,
+			UriInfo ui) throws BadStateChangeException,
+			BadPropertyValueException, FilesystemAccessException {
+		URITemplate tmpl = new URITemplate(ui.getBaseUri()
+				+ "/runs/{runName}/wd/{path:.+}");
+		MultivaluedMap<String, String> mvm = new MetadataMap<>();
+		if (!tmpl.match(ref.contents, mvm)) {
+			throw new BadPropertyValueException(
+					"URI in reference does not refer to local disk resource");
+		}
+		try {
+			File from = fileUtils.getFile(
+					support.getRun(mvm.get("runName").get(0)),
+					SyntheticDirectoryEntry.make(mvm.get("path").get(0)));
+			File to = run.getWorkingDirectory().makeEmptyFile(
+					support.getPrincipal(), randomUUID().toString());
+
+			to.copy(from);
+
+			Input i = support.getInput(run, name);
+			if (i == null)
+				i = run.makeInput(name);
+			i.setFile(to.getFullName());
+			i.setDelimiter(delimiter);
+			return new InDesc(i, ui);
+		} catch (UnknownRunException e) {
+			throw new BadStateChangeException("may not copy from that run", e);
+		} catch (NoDirectoryEntryException e) {
+			throw new BadStateChangeException("source does not exist", e);
+		}
+	}
+
+	@Override
+	@CallCounted
+	public Response options() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response expectedOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response baclavaOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response inputOptions(@PathParam("name") String name) {
+		return opt("PUT");
+	}
+}
+
+/**
+ * A way to create synthetic directory entries, used during deletion.
+ * 
+ * @author Donal Fellows
+ */
+class SyntheticDirectoryEntry implements DirectoryEntry {
+	public static DirEntryReference make(String path) {
+		return DirEntryReference.newInstance(new SyntheticDirectoryEntry(path));
+	}
+
+	private SyntheticDirectoryEntry(String p) {
+		this.p = p;
+		this.d = new Date();
+	}
+
+	private String p;
+	private Date d;
+
+	@Override
+	public String getName() {
+		return null;
+	}
+
+	@Override
+	public String getFullName() {
+		return p;
+	}
+
+	@Override
+	public void destroy() {
+	}
+
+	@Override
+	public int compareTo(DirectoryEntry o) {
+		return p.compareTo(o.getFullName());
+	}
+
+	@Override
+	public Date getModificationDate() {
+		return d;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InteractionFeed.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InteractionFeed.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InteractionFeed.java
new file mode 100644
index 0000000..6dfa3e2
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InteractionFeed.java
@@ -0,0 +1,120 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Roles.SELF;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.core.Response;
+
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.taverna.server.master.api.FeedBean;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interaction.InteractionFeedSupport;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.InteractionFeedREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * How to connect an interaction feed to the webapp.
+ * 
+ * @author Donal Fellows
+ */
+public class InteractionFeed implements InteractionFeedREST, FeedBean {
+	private InteractionFeedSupport interactionFeed;
+	private TavernaRun run;
+
+	@Override
+	public void setInteractionFeedSupport(InteractionFeedSupport feed) {
+		this.interactionFeed = feed;
+	}
+
+	InteractionFeed connect(TavernaRun run) {
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Feed getFeed() throws FilesystemAccessException,
+			NoDirectoryEntryException {
+		return interactionFeed.getRunFeed(run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response addEntry(Entry entry) throws MalformedURLException,
+			FilesystemAccessException, NoDirectoryEntryException,
+			NoUpdateException {
+		Entry realEntry = interactionFeed.addRunFeedEntry(run, entry);
+		URI location;
+		try {
+			location = realEntry.getSelfLink().getHref().toURI();
+		} catch (URISyntaxException e) {
+			throw new RuntimeException("failed to make URI from link?!", e);
+		}
+		return Response.created(location).entity(realEntry)
+				.type("application/atom+xml;type=entry").build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Entry getEntry(String id) throws FilesystemAccessException,
+			NoDirectoryEntryException {
+		return interactionFeed.getRunFeedEntry(run, id);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public String deleteEntry(String id) throws FilesystemAccessException,
+			NoDirectoryEntryException, NoUpdateException {
+		interactionFeed.removeRunFeedEntry(run, id);
+		return "entry successfully deleted";
+	}
+
+	@Override
+	@CallCounted
+	public Response feedOptions() {
+		return opt("POST");
+	}
+
+	@Override
+	@CallCounted
+	public Response entryOptions(String id) {
+		return opt("DELETE");
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenerPropertyREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenerPropertyREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenerPropertyREST.java
new file mode 100644
index 0000000..26a8982
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenerPropertyREST.java
@@ -0,0 +1,91 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.commons.logging.Log;
+import org.taverna.server.master.api.ListenerPropertyBean;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful interface to a single property of a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+class ListenerPropertyREST implements TavernaServerListenersREST.Property,
+		ListenerPropertyBean {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private TavernaServerSupport support;
+	private Listener listen;
+	private String propertyName;
+	private TavernaRun run;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	public ListenerPropertyREST connect(Listener listen, TavernaRun run,
+			String propertyName) {
+		this.listen = listen;
+		this.propertyName = propertyName;
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String getValue() {
+		try {
+			return listen.getProperty(propertyName);
+		} catch (NoListenerException e) {
+			log.error("unexpected exception; property \"" + propertyName
+					+ "\" should exist", e);
+			return null;
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String setValue(String value) throws NoUpdateException,
+			NoListenerException {
+		support.permitUpdate(run);
+		listen.setProperty(propertyName, value);
+		return listen.getProperty(propertyName);
+	}
+
+	@Override
+	@CallCounted
+	public Response options() {
+		return opt("PUT");
+	}
+}
\ No newline at end of file


[19/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java
deleted file mode 100644
index b800c1c..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
-import static javax.ws.rs.core.Response.created;
-import static javax.ws.rs.core.Response.noContent;
-import static javax.ws.rs.core.Response.ok;
-import static javax.ws.rs.core.Response.seeOther;
-import static javax.ws.rs.core.Response.status;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
-import static org.taverna.server.master.api.ContentTypes.DIRECTORY_VARIANTS;
-import static org.taverna.server.master.api.ContentTypes.INITIAL_FILE_VARIANTS;
-import static org.taverna.server.master.common.Roles.SELF;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.PathSegment;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.ws.rs.core.Variant;
-import javax.xml.ws.Holder;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.DirectoryBean;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.DirectoryContents;
-import org.taverna.server.master.rest.FileSegment;
-import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
-import org.taverna.server.master.rest.MakeOrUpdateDirEntry.MakeDirectory;
-import org.taverna.server.master.rest.TavernaServerDirectoryREST;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful access to the filesystem.
- * 
- * @author Donal Fellows
- */
-class DirectoryREST implements TavernaServerDirectoryREST, DirectoryBean {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private TavernaServerSupport support;
-	private TavernaRun run;
-	private FilenameUtils fileUtils;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	@Required
-	public void setFileUtils(FilenameUtils fileUtils) {
-		this.fileUtils = fileUtils;
-	}
-
-	@Override
-	public DirectoryREST connect(TavernaRun run) {
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response destroyDirectoryEntry(List<PathSegment> path)
-			throws NoUpdateException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		support.permitUpdate(run);
-		fileUtils.getDirEntry(run, path).destroy();
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public DirectoryContents getDescription(UriInfo ui)
-			throws FilesystemAccessException {
-		return new DirectoryContents(ui, run.getWorkingDirectory()
-				.getContents());
-	}
-
-	@Override
-	@CallCounted
-	public Response options(List<PathSegment> path) {
-		return opt("PUT", "POST", "DELETE");
-	}
-
-	/*
-	 * // Nasty! This can have several different responses...
-	 * 
-	 * @Override @CallCounted private Response
-	 * getDirectoryOrFileContents(List<PathSegment> path, UriInfo ui, Request
-	 * req) throws FilesystemAccessException, NoDirectoryEntryException {
-	 * 
-	 * DirectoryEntry de = fileUtils.getDirEntry(run, path);
-	 * 
-	 * // How did the user want the result?
-	 * 
-	 * List<Variant> variants = getVariants(de); Variant v =
-	 * req.selectVariant(variants); if (v == null) return
-	 * notAcceptable(variants).type(TEXT_PLAIN)
-	 * .entity("Do not know what type of response to produce.") .build();
-	 * 
-	 * // Produce the content to deliver up
-	 * 
-	 * Object result; if
-	 * (v.getMediaType().equals(APPLICATION_OCTET_STREAM_TYPE))
-	 * 
-	 * // Only for files...
-	 * 
-	 * result = de; else if (v.getMediaType().equals(APPLICATION_ZIP_TYPE))
-	 * 
-	 * // Only for directories...
-	 * 
-	 * result = ((Directory) de).getContentsAsZip(); else
-	 * 
-	 * // Only for directories... // XML or JSON; let CXF pick what to do
-	 * 
-	 * result = new DirectoryContents(ui, ((Directory) de).getContents());
-	 * return ok(result).type(v.getMediaType()).build();
-	 * 
-	 * }
-	 */
-
-	private boolean matchType(MediaType a, MediaType b) {
-		if (log.isDebugEnabled())
-			log.debug("comparing " + a.getType() + "/" + a.getSubtype()
-					+ " and " + b.getType() + "/" + b.getSubtype());
-		return (a.isWildcardType() || b.isWildcardType() || a.getType().equals(
-				b.getType()))
-				&& (a.isWildcardSubtype() || b.isWildcardSubtype() || a
-						.getSubtype().equals(b.getSubtype()));
-	}
-
-	/**
-	 * What are we willing to serve up a directory or file as?
-	 * 
-	 * @param de
-	 *            The reference to the object to serve.
-	 * @return The variants we can serve it as.
-	 * @throws FilesystemAccessException
-	 *             If we fail to read data necessary to detection of its media
-	 *             type.
-	 */
-	private List<Variant> getVariants(DirectoryEntry de)
-			throws FilesystemAccessException {
-		if (de instanceof Directory)
-			return DIRECTORY_VARIANTS;
-		else if (!(de instanceof File))
-			throw new FilesystemAccessException("not a directory or file!");
-		File f = (File) de;
-		List<Variant> variants = new ArrayList<>(INITIAL_FILE_VARIANTS);
-		String contentType = support.getEstimatedContentType(f);
-		if (!contentType.equals(APPLICATION_OCTET_STREAM)) {
-			String[] ct = contentType.split("/");
-			variants.add(0,
-					new Variant(new MediaType(ct[0], ct[1]), (String) null, null));
-		}
-		return variants;
-	}
-
-	/** How did the user want the result? */
-	private MediaType pickType(HttpHeaders headers, DirectoryEntry de)
-			throws FilesystemAccessException, NegotiationFailedException {
-		List<Variant> variants = getVariants(de);
-		// Manual content negotiation!!! Ugh!
-		for (MediaType mt : headers.getAcceptableMediaTypes())
-			for (Variant v : variants)
-				if (matchType(mt, v.getMediaType()))
-					return v.getMediaType();
-		throw new NegotiationFailedException(
-				"Do not know what type of response to produce.", variants);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response getDirectoryOrFileContents(List<PathSegment> path,
-			UriInfo ui, HttpHeaders headers) throws FilesystemAccessException,
-			NoDirectoryEntryException, NegotiationFailedException {
-		DirectoryEntry de = fileUtils.getDirEntry(run, path);
-
-		// How did the user want the result?
-		MediaType wanted = pickType(headers, de);
-
-		log.info("producing content of type " + wanted);
-		// Produce the content to deliver up
-		Object result;
-		if (de instanceof File) {
-			// Only for files...
-			result = de;
-			List<String> range = headers.getRequestHeader("Range");
-			if (range != null && range.size() == 1)
-				return new FileSegment((File) de, range.get(0))
-						.toResponse(wanted);
-		} else {
-			// Only for directories...
-			Directory d = (Directory) de;
-			if (wanted.getType().equals(APPLICATION_ZIP_TYPE.getType())
-					&& wanted.getSubtype().equals(
-							APPLICATION_ZIP_TYPE.getSubtype()))
-				result = d.getContentsAsZip();
-			else
-				// XML or JSON; let CXF pick what to do
-				result = new DirectoryContents(ui, d.getContents());
-		}
-		return ok(result).type(wanted).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response makeDirectoryOrUpdateFile(List<PathSegment> parent,
-			MakeOrUpdateDirEntry op, UriInfo ui) throws NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException {
-		support.permitUpdate(run);
-		DirectoryEntry container = fileUtils.getDirEntry(run, parent);
-		if (!(container instanceof Directory))
-			throw new FilesystemAccessException("You may not "
-					+ ((op instanceof MakeDirectory) ? "make a subdirectory of"
-							: "place a file in") + " a file.");
-		if (op.name == null || op.name.length() == 0)
-			throw new FilesystemAccessException("missing name attribute");
-		Directory d = (Directory) container;
-		UriBuilder ub = secure(ui).path("{name}");
-
-		// Make a directory in the context directory
-
-		if (op instanceof MakeDirectory) {
-			Directory target = d.makeSubdirectory(support.getPrincipal(),
-					op.name);
-			return created(ub.build(target.getName())).build();
-		}
-
-		// Make or set the contents of a file
-
-		File f = null;
-		for (DirectoryEntry e : d.getContents()) {
-			if (e.getName().equals(op.name)) {
-				if (e instanceof Directory)
-					throw new FilesystemAccessException(
-							"You may not overwrite a directory with a file.");
-				f = (File) e;
-				break;
-			}
-		}
-		if (f == null) {
-			f = d.makeEmptyFile(support.getPrincipal(), op.name);
-			f.setContents(op.contents);
-			return created(ub.build(f.getName())).build();
-		}
-		f.setContents(op.contents);
-		return seeOther(ub.build(f.getName())).build();
-	}
-
-	private File getFileForWrite(List<PathSegment> filePath,
-			Holder<Boolean> isNew) throws FilesystemAccessException,
-			NoDirectoryEntryException, NoUpdateException {
-		support.permitUpdate(run);
-		if (filePath == null || filePath.size() == 0)
-			throw new FilesystemAccessException(
-					"Cannot create a file that is not in a directory.");
-
-		List<PathSegment> dirPath = new ArrayList<>(filePath);
-		String name = dirPath.remove(dirPath.size() - 1).getPath();
-		DirectoryEntry de = fileUtils.getDirEntry(run, dirPath);
-		if (!(de instanceof Directory)) {
-			throw new FilesystemAccessException(
-					"Cannot create a file that is not in a directory.");
-		}
-		Directory d = (Directory) de;
-
-		File f = null;
-		isNew.value = false;
-		for (DirectoryEntry e : d.getContents())
-			if (e.getName().equals(name)) {
-				if (e instanceof File) {
-					f = (File) e;
-					break;
-				}
-				throw new FilesystemAccessException(
-						"Cannot create a file that is not in a directory.");
-			}
-
-		if (f == null) {
-			f = d.makeEmptyFile(support.getPrincipal(), name);
-			isNew.value = true;
-		} else
-			f.setContents(new byte[0]);
-		return f;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response setFileContents(List<PathSegment> filePath,
-			InputStream contents, UriInfo ui) throws NoDirectoryEntryException,
-			NoUpdateException, FilesystemAccessException {
-		Holder<Boolean> isNew = new Holder<>(true);
-		support.copyStreamToFile(contents, getFileForWrite(filePath, isNew));
-
-		if (isNew.value)
-			return created(ui.getAbsolutePath()).build();
-		else
-			return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response setFileContentsFromURL(List<PathSegment> filePath,
-			List<URI> referenceList, UriInfo ui)
-			throws NoDirectoryEntryException, NoUpdateException,
-			FilesystemAccessException {
-		support.permitUpdate(run);
-		if (referenceList.isEmpty() || referenceList.size() > 1)
-			return status(422).entity("URI list must have single URI in it")
-					.build();
-		URI uri = referenceList.get(0);
-		try {
-			uri.toURL();
-		} catch (MalformedURLException e) {
-			return status(422).entity("URI list must have value URL in it")
-					.build();
-		}
-		Holder<Boolean> isNew = new Holder<>(true);
-		File f = getFileForWrite(filePath, isNew);
-
-		try {
-			support.copyDataToFile(uri, f);
-		} catch (MalformedURLException ex) {
-			// Should not happen; called uri.toURL() successfully above
-			throw new NoUpdateException("failed to parse URI", ex);
-		} catch (IOException ex) {
-			throw new FilesystemAccessException(
-					"failed to transfer data from URI", ex);
-		}
-
-		if (isNew.value)
-			return created(ui.getAbsolutePath()).build();
-		else
-			return noContent().build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java
deleted file mode 100644
index 4ccb033..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-/**
- * Simple concatenation of files.
- * 
- * @author Donal Fellows
- */
-public class FileConcatenation implements Iterable<File> {
-	private List<File> files = new ArrayList<>();
-
-	public void add(File f) {
-		files.add(f);
-	}
-
-	public boolean isEmpty() {
-		return files.isEmpty();
-	}
-
-	/**
-	 * @return The total length of the files, or -1 if this cannot be
-	 *         determined.
-	 */
-	public long size() {
-		long size = 0;
-		for (File f : files)
-			try {
-				size += f.getSize();
-			} catch (FilesystemAccessException e) {
-				// Ignore; shouldn't happen but can't guarantee
-			}
-		return (size == 0 && !files.isEmpty() ? -1 : size);
-	}
-
-	/**
-	 * Get the concatenated files.
-	 * 
-	 * @param encoding
-	 *            The encoding to use.
-	 * @return The concatenated files.
-	 * @throws UnsupportedEncodingException
-	 *             If the encoding doesn't exist.
-	 */
-	public String get(String encoding) throws UnsupportedEncodingException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		for (File f : files)
-			try {
-				baos.write(f.getContents(0, -1));
-			} catch (FilesystemAccessException | IOException e) {
-				continue;
-			}
-		return baos.toString(encoding);
-	}
-
-	@Override
-	public Iterator<File> iterator() {
-		return files.iterator();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/InputREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/InputREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/InputREST.java
deleted file mode 100644
index b9c8f55..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/InputREST.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.util.Date;
-
-import javax.ws.rs.PathParam;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.cxf.jaxrs.impl.MetadataMap;
-import org.apache.cxf.jaxrs.model.URITemplate;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.InputBean;
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.exceptions.BadInputPortNameException;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerInputREST;
-import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.AbstractContents;
-import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.Reference;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-import org.taverna.server.port_description.InputDescription;
-
-/**
- * RESTful interface to the input descriptor of a single workflow run.
- * 
- * @author Donal Fellows
- */
-class InputREST implements TavernaServerInputREST, InputBean {
-	private UriInfo ui;
-	private TavernaServerSupport support;
-	private TavernaRun run;
-	private ContentsDescriptorBuilder cdBuilder;
-	private FilenameUtils fileUtils;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	@Required
-	public void setCdBuilder(ContentsDescriptorBuilder cdBuilder) {
-		this.cdBuilder = cdBuilder;
-	}
-
-	@Override
-	@Required
-	public void setFileUtils(FilenameUtils fileUtils) {
-		this.fileUtils = fileUtils;
-	}
-
-	@Override
-	public InputREST connect(TavernaRun run, UriInfo ui) {
-		this.run = run;
-		this.ui = ui;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public InputsDescriptor get() {
-		return new InputsDescriptor(ui, run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public InputDescription getExpected() {
-		return cdBuilder.makeInputDescriptor(run, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String getBaclavaFile() {
-		String i = run.getInputBaclavaFile();
-		return i == null ? "" : i;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public InDesc getInput(String name, UriInfo ui) throws BadInputPortNameException {
-		Input i = support.getInput(run, name);
-		if (i == null)
-			throw new BadInputPortNameException("unknown input port name");
-		return new InDesc(i, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String setBaclavaFile(String filename) throws NoUpdateException,
-			BadStateChangeException, FilesystemAccessException {
-		support.permitUpdate(run);
-		run.setInputBaclavaFile(filename);
-		String i = run.getInputBaclavaFile();
-		return i == null ? "" : i;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public InDesc setInput(String name, InDesc inputDescriptor, UriInfo ui)
-			throws NoUpdateException, BadStateChangeException,
-			FilesystemAccessException, BadInputPortNameException,
-			BadPropertyValueException {
-		inputDescriptor.descriptorRef = null;
-		AbstractContents ac = inputDescriptor.assignment;
-		if (name == null || name.isEmpty())
-			throw new BadInputPortNameException("bad input name");
-		if (ac == null)
-			throw new BadPropertyValueException("no content!");
-		if (inputDescriptor.delimiter != null
-				&& inputDescriptor.delimiter.isEmpty())
-			inputDescriptor.delimiter = null;
-		if (ac instanceof InDesc.Reference)
-			return setRemoteInput(name, (InDesc.Reference) ac,
-					inputDescriptor.delimiter, ui);
-		if (!(ac instanceof InDesc.File || ac instanceof InDesc.Value))
-			throw new BadPropertyValueException("unknown content type");
-		support.permitUpdate(run);
-		Input i = support.getInput(run, name);
-		if (i == null)
-			i = run.makeInput(name);
-		if (ac instanceof InDesc.File)
-			i.setFile(ac.contents);
-		else
-			i.setValue(ac.contents);
-		i.setDelimiter(inputDescriptor.delimiter);
-		return new InDesc(i, ui);
-	}
-
-	private InDesc setRemoteInput(String name, Reference ref, String delimiter,
-			UriInfo ui) throws BadStateChangeException,
-			BadPropertyValueException, FilesystemAccessException {
-		URITemplate tmpl = new URITemplate(ui.getBaseUri()
-				+ "/runs/{runName}/wd/{path:.+}");
-		MultivaluedMap<String, String> mvm = new MetadataMap<>();
-		if (!tmpl.match(ref.contents, mvm)) {
-			throw new BadPropertyValueException(
-					"URI in reference does not refer to local disk resource");
-		}
-		try {
-			File from = fileUtils.getFile(
-					support.getRun(mvm.get("runName").get(0)),
-					SyntheticDirectoryEntry.make(mvm.get("path").get(0)));
-			File to = run.getWorkingDirectory().makeEmptyFile(
-					support.getPrincipal(), randomUUID().toString());
-
-			to.copy(from);
-
-			Input i = support.getInput(run, name);
-			if (i == null)
-				i = run.makeInput(name);
-			i.setFile(to.getFullName());
-			i.setDelimiter(delimiter);
-			return new InDesc(i, ui);
-		} catch (UnknownRunException e) {
-			throw new BadStateChangeException("may not copy from that run", e);
-		} catch (NoDirectoryEntryException e) {
-			throw new BadStateChangeException("source does not exist", e);
-		}
-	}
-
-	@Override
-	@CallCounted
-	public Response options() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response expectedOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response baclavaOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response inputOptions(@PathParam("name") String name) {
-		return opt("PUT");
-	}
-}
-
-/**
- * A way to create synthetic directory entries, used during deletion.
- * 
- * @author Donal Fellows
- */
-class SyntheticDirectoryEntry implements DirectoryEntry {
-	public static DirEntryReference make(String path) {
-		return DirEntryReference.newInstance(new SyntheticDirectoryEntry(path));
-	}
-
-	private SyntheticDirectoryEntry(String p) {
-		this.p = p;
-		this.d = new Date();
-	}
-
-	private String p;
-	private Date d;
-
-	@Override
-	public String getName() {
-		return null;
-	}
-
-	@Override
-	public String getFullName() {
-		return p;
-	}
-
-	@Override
-	public void destroy() {
-	}
-
-	@Override
-	public int compareTo(DirectoryEntry o) {
-		return p.compareTo(o.getFullName());
-	}
-
-	@Override
-	public Date getModificationDate() {
-		return d;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java
deleted file mode 100644
index 6dfa3e2..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Roles.SELF;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.core.Response;
-
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.model.Feed;
-import org.taverna.server.master.api.FeedBean;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interaction.InteractionFeedSupport;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.InteractionFeedREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * How to connect an interaction feed to the webapp.
- * 
- * @author Donal Fellows
- */
-public class InteractionFeed implements InteractionFeedREST, FeedBean {
-	private InteractionFeedSupport interactionFeed;
-	private TavernaRun run;
-
-	@Override
-	public void setInteractionFeedSupport(InteractionFeedSupport feed) {
-		this.interactionFeed = feed;
-	}
-
-	InteractionFeed connect(TavernaRun run) {
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Feed getFeed() throws FilesystemAccessException,
-			NoDirectoryEntryException {
-		return interactionFeed.getRunFeed(run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response addEntry(Entry entry) throws MalformedURLException,
-			FilesystemAccessException, NoDirectoryEntryException,
-			NoUpdateException {
-		Entry realEntry = interactionFeed.addRunFeedEntry(run, entry);
-		URI location;
-		try {
-			location = realEntry.getSelfLink().getHref().toURI();
-		} catch (URISyntaxException e) {
-			throw new RuntimeException("failed to make URI from link?!", e);
-		}
-		return Response.created(location).entity(realEntry)
-				.type("application/atom+xml;type=entry").build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Entry getEntry(String id) throws FilesystemAccessException,
-			NoDirectoryEntryException {
-		return interactionFeed.getRunFeedEntry(run, id);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public String deleteEntry(String id) throws FilesystemAccessException,
-			NoDirectoryEntryException, NoUpdateException {
-		interactionFeed.removeRunFeedEntry(run, id);
-		return "entry successfully deleted";
-	}
-
-	@Override
-	@CallCounted
-	public Response feedOptions() {
-		return opt("POST");
-	}
-
-	@Override
-	@CallCounted
-	public Response entryOptions(String id) {
-		return opt("DELETE");
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java
deleted file mode 100644
index 26a8982..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import javax.ws.rs.core.Response;
-
-import org.apache.commons.logging.Log;
-import org.taverna.server.master.api.ListenerPropertyBean;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful interface to a single property of a workflow run.
- * 
- * @author Donal Fellows
- */
-class ListenerPropertyREST implements TavernaServerListenersREST.Property,
-		ListenerPropertyBean {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private TavernaServerSupport support;
-	private Listener listen;
-	private String propertyName;
-	private TavernaRun run;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	public ListenerPropertyREST connect(Listener listen, TavernaRun run,
-			String propertyName) {
-		this.listen = listen;
-		this.propertyName = propertyName;
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String getValue() {
-		try {
-			return listen.getProperty(propertyName);
-		} catch (NoListenerException e) {
-			log.error("unexpected exception; property \"" + propertyName
-					+ "\" should exist", e);
-			return null;
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String setValue(String value) throws NoUpdateException,
-			NoListenerException {
-		support.permitUpdate(run);
-		listen.setProperty(propertyName, value);
-		return listen.getProperty(propertyName);
-	}
-
-	@Override
-	@CallCounted
-	public Response options() {
-		return opt("PUT");
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java
deleted file mode 100644
index 3cc0d73..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.created;
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-
-import org.taverna.server.master.api.ListenersBean;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.ListenerDefinition;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful interface to a single workflow run's event listeners.
- * 
- * @author Donal Fellows
- */
-abstract class ListenersREST implements TavernaServerListenersREST,
-		ListenersBean {
-	private TavernaRun run;
-	private TavernaServerSupport support;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	public ListenersREST connect(TavernaRun run) {
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response addListener(ListenerDefinition typeAndConfiguration,
-			UriInfo ui) throws NoUpdateException, NoListenerException {
-		String name = support.makeListener(run, typeAndConfiguration.type,
-				typeAndConfiguration.configuration).getName();
-		return created(secure(ui).path("{listenerName}").build(name)).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public TavernaServerListenerREST getListener(String name)
-			throws NoListenerException {
-		Listener l = support.getListener(run, name);
-		if (l == null)
-			throw new NoListenerException();
-		return makeListenerInterface().connect(l, run);
-	}
-
-	@Nonnull
-	protected abstract SingleListenerREST makeListenerInterface();
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Listeners getDescription(UriInfo ui) {
-		List<ListenerDescription> result = new ArrayList<>();
-		UriBuilder ub = secure(ui).path("{name}");
-		for (Listener l : run.getListeners())
-			result.add(new ListenerDescription(l,
-					fromUri(ub.build(l.getName()))));
-		return new Listeners(result, ub);
-	}
-
-	@Override
-	@CallCounted
-	public Response listenersOptions() {
-		return opt();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/ManagementState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/ManagementState.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/ManagementState.java
deleted file mode 100644
index c65a334..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/ManagementState.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import javax.annotation.PostConstruct;
-import javax.jdo.Query;
-import javax.jdo.annotations.PersistenceAware;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.PrimaryKey;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.utils.JDOSupport;
-
-/** The persistent, manageable state of the Taverna Server web application. */
-@PersistenceAware
-class ManagementState extends JDOSupport<WebappState> implements
-		ManagementModel {
-	public ManagementState() {
-		super(WebappState.class);
-	}
-
-	/** Whether we should log all workflows sent to us. */
-	private boolean logIncomingWorkflows = false;
-
-	/** Whether we allow the creation of new workflow runs. */
-	private boolean allowNewWorkflowRuns = true;
-
-	/**
-	 * Whether outgoing exceptions should be logged before being converted to
-	 * responses.
-	 */
-	private boolean logOutgoingExceptions = false;
-
-	/**
-	 * The file that all usage records should be appended to, or <tt>null</tt>
-	 * if they should be just dropped.
-	 */
-	private String usageRecordLogFile = null;
-
-	@Override
-	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
-		this.logIncomingWorkflows = logIncomingWorkflows;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public boolean getLogIncomingWorkflows() {
-		self.load();
-		return logIncomingWorkflows;
-	}
-
-	@Override
-	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
-		this.allowNewWorkflowRuns = allowNewWorkflowRuns;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public boolean getAllowNewWorkflowRuns() {
-		self.load();
-		return allowNewWorkflowRuns;
-	}
-
-	@Override
-	public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
-		this.logOutgoingExceptions = logOutgoingExceptions;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public boolean getLogOutgoingExceptions() {
-		self.load();
-		return logOutgoingExceptions || true;
-	}
-
-	@Override
-	public String getUsageRecordLogFile() {
-		self.load();
-		return usageRecordLogFile;
-	}
-
-	@Override
-	public void setUsageRecordLogFile(String usageRecordLogFile) {
-		this.usageRecordLogFile = usageRecordLogFile;
-		if (loadedState)
-			self.store();
-	}
-
-	private static final int KEY = 42; // whatever
-
-	private WebappState get() {
-		Query<WebappState> q = query("id == " + KEY);
-		q.setUnique(true);
-		return q.executeUnique();
-	}
-
-	private boolean loadedState;
-	private ManagementState self;
-
-	@Required
-	public void setSelf(ManagementState self) {
-		this.self = self;
-	}
-
-	@PostConstruct
-	@WithinSingleTransaction
-	public void load() {
-		if (loadedState || !isPersistent())
-			return;
-		WebappState state = get();
-		if (state == null)
-			return;
-		allowNewWorkflowRuns = state.getAllowNewWorkflowRuns();
-		logIncomingWorkflows = state.getLogIncomingWorkflows();
-		logOutgoingExceptions = state.getLogOutgoingExceptions();
-		usageRecordLogFile = state.getUsageRecordLogFile();
-		loadedState = true;
-	}
-
-	@WithinSingleTransaction
-	public void store() {
-		if (!isPersistent())
-			return;
-		WebappState state = get();
-		if (state == null) {
-			state = new WebappState();
-			// save state
-			state.id = KEY; // whatever...
-			state = persist(state);
-		}
-		state.setAllowNewWorkflowRuns(allowNewWorkflowRuns);
-		state.setLogIncomingWorkflows(logIncomingWorkflows);
-		state.setLogOutgoingExceptions(logOutgoingExceptions);
-		state.setUsageRecordLogFile(usageRecordLogFile);
-		loadedState = true;
-	}
-}
-
-// WARNING! If you change the name of this class, update persistence.xml as
-// well!
-@PersistenceCapable(table = "MANAGEMENTSTATE__WEBAPPSTATE")
-class WebappState implements ManagementModel {
-	public WebappState() {
-	}
-
-	@PrimaryKey
-	protected int id;
-
-	/** Whether we should log all workflows sent to us. */
-	@Persistent
-	private boolean logIncomingWorkflows;
-
-	/** Whether we allow the creation of new workflow runs. */
-	@Persistent
-	private boolean allowNewWorkflowRuns;
-
-	/**
-	 * Whether outgoing exceptions should be logged before being converted to
-	 * responses.
-	 */
-	@Persistent
-	private boolean logOutgoingExceptions;
-
-	/** Where to write usage records. */
-	@Persistent
-	private String usageRecordLogFile;
-
-	@Override
-	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
-		this.logIncomingWorkflows = logIncomingWorkflows;
-	}
-
-	@Override
-	public boolean getLogIncomingWorkflows() {
-		return logIncomingWorkflows;
-	}
-
-	@Override
-	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
-		this.allowNewWorkflowRuns = allowNewWorkflowRuns;
-	}
-
-	@Override
-	public boolean getAllowNewWorkflowRuns() {
-		return allowNewWorkflowRuns;
-	}
-
-	@Override
-	public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
-		this.logOutgoingExceptions = logOutgoingExceptions;
-	}
-
-	@Override
-	public boolean getLogOutgoingExceptions() {
-		return logOutgoingExceptions;
-	}
-
-	@Override
-	public String getUsageRecordLogFile() {
-		return usageRecordLogFile;
-	}
-
-	@Override
-	public void setUsageRecordLogFile(String usageRecordLogFile) {
-		this.usageRecordLogFile = usageRecordLogFile;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/RunREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/RunREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/RunREST.java
deleted file mode 100644
index a04de46..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/RunREST.java
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.MediaType.APPLICATION_XML;
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
-import static javax.ws.rs.core.Response.noContent;
-import static javax.ws.rs.core.Response.ok;
-import static javax.ws.rs.core.Response.status;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.joda.time.format.ISODateTimeFormat.dateTime;
-import static org.joda.time.format.ISODateTimeFormat.dateTimeParser;
-import static org.taverna.server.master.common.Roles.SELF;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.common.Status.Initialized;
-import static org.taverna.server.master.common.Status.Operating;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.util.Date;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.logging.Log;
-import org.joda.time.DateTime;
-import org.apache.taverna.server.usagerecord.JobUsageRecord;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.RunBean;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.NotOwnerException;
-import org.taverna.server.master.exceptions.OverloadedException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.InteractionFeedREST;
-import org.taverna.server.master.rest.TavernaServerInputREST;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.rest.TavernaServerRunREST;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-import org.taverna.server.port_description.OutputDescription;
-
-/**
- * RESTful interface to a single workflow run.
- * 
- * @author Donal Fellows
- */
-abstract class RunREST implements TavernaServerRunREST, RunBean {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private String runName;
-	private TavernaRun run;
-	private TavernaServerSupport support;
-	private ContentsDescriptorBuilder cdBuilder;
-
-	@Override
-	@Required
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	@Required
-	public void setCdBuilder(ContentsDescriptorBuilder cdBuilder) {
-		this.cdBuilder = cdBuilder;
-	}
-
-	@Override
-	public void setRunName(String runName) {
-		this.runName = runName;
-	}
-
-	@Override
-	public void setRun(TavernaRun run) {
-		this.run = run;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public RunDescription getDescription(UriInfo ui) {
-		return new RunDescription(run, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response destroy() throws NoUpdateException {
-		try {
-			support.unregisterRun(runName, run);
-		} catch (UnknownRunException e) {
-			log.fatal("can't happen", e);
-		}
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public TavernaServerListenersREST getListeners() {
-		return makeListenersInterface().connect(run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public TavernaServerSecurityREST getSecurity() throws NotOwnerException {
-		TavernaSecurityContext secContext = run.getSecurityContext();
-		if (!support.getPrincipal().equals(secContext.getOwner()))
-			throw new NotOwnerException();
-
-		// context.getBean("run.security", run, secContext);
-		return makeSecurityInterface().connect(secContext, run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getExpiryTime() {
-		return dateTime().print(new DateTime(run.getExpiry()));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getCreateTime() {
-		return dateTime().print(new DateTime(run.getCreationTimestamp()));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getFinishTime() {
-		Date f = run.getFinishTimestamp();
-		return f == null ? "" : dateTime().print(new DateTime(f));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getStartTime() {
-		Date f = run.getStartTimestamp();
-		return f == null ? "" : dateTime().print(new DateTime(f));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getStatus() {
-		return run.getStatus().toString();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Workflow getWorkflow() {
-		return run.getWorkflow();
-	}
-
-	@Override
-	@CallCounted
-	public String getMainProfileName() {
-		String name = run.getWorkflow().getMainProfileName();
-		return (name == null ? "" : name);
-	}
-
-	@Override
-	@CallCounted
-	public ProfileList getProfiles() {
-		return support.getProfileDescriptor(run.getWorkflow());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public DirectoryREST getWorkingDirectory() {
-		return makeDirectoryInterface().connect(run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String setExpiryTime(String expiry) throws NoUpdateException,
-			IllegalArgumentException {
-		DateTime wanted = dateTimeParser().parseDateTime(expiry.trim());
-		Date achieved = support.updateExpiry(run, wanted.toDate());
-		return dateTime().print(new DateTime(achieved));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response setStatus(String status) throws NoUpdateException {
-		Status newStatus = Status.valueOf(status.trim());
-		support.permitUpdate(run);
-		if (newStatus == Operating && run.getStatus() == Initialized) {
-			if (!support.getAllowStartWorkflowRuns())
-				throw new OverloadedException();
-			String issue = run.setStatus(newStatus);
-			if (issue == null)
-				issue = "starting run...";
-			return status(202).entity(issue).type("text/plain").build();
-		}
-		run.setStatus(newStatus); // Ignore the result
-		return ok(run.getStatus().toString()).type("text/plain").build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public TavernaServerInputREST getInputs(UriInfo ui) {
-		return makeInputInterface().connect(run, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getOutputFile() {
-		String o = run.getOutputBaclavaFile();
-		return o == null ? "" : o;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String setOutputFile(String filename) throws NoUpdateException,
-			FilesystemAccessException, BadStateChangeException {
-		support.permitUpdate(run);
-		if (filename != null && filename.length() == 0)
-			filename = null;
-		run.setOutputBaclavaFile(filename);
-		String o = run.getOutputBaclavaFile();
-		return o == null ? "" : o;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public OutputDescription getOutputDescription(UriInfo ui)
-			throws BadStateChangeException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		if (run.getStatus() == Initialized)
-			throw new BadStateChangeException(
-					"may not get output description in initial state");
-		return cdBuilder.makeOutputDescriptor(run, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public InteractionFeedREST getInteractionFeed() {
-		return makeInteractionFeed().connect(run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getName() {
-		return run.getName();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String setName(String name) throws NoUpdateException {
-		support.permitUpdate(run);
-		run.setName(name);
-		return run.getName();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getStdout() throws NoListenerException {
-		return support.getProperty(run, "io", "stdout");
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getStderr() throws NoListenerException {
-		return support.getProperty(run, "io", "stderr");
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response getUsage() throws NoListenerException, JAXBException {
-		String ur = support.getProperty(run, "io", "usageRecord");
-		if (ur.isEmpty())
-			return noContent().build();
-		return ok(JobUsageRecord.unmarshal(ur), APPLICATION_XML).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response getLogContents() {
-		FileConcatenation fc = support.getLogs(run);
-		if (fc.isEmpty())
-			return Response.noContent().build();
-		return Response.ok(fc, TEXT_PLAIN).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response getRunBundle() {
-		FileConcatenation fc = support.getProv(run);
-		if (fc.isEmpty())
-			return Response.status(404).entity("no provenance currently available").build();
-		return Response.ok(fc, "application/vnd.wf4ever.robundle+zip").build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public boolean getGenerateProvenance() {
-		return run.getGenerateProvenance();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public boolean setGenerateProvenance(boolean newValue) throws NoUpdateException {
-		support.permitUpdate(run);
-		run.setGenerateProvenance(newValue);
-		return run.getGenerateProvenance();
-	}
-
-	/**
-	 * Construct a RESTful interface to a run's filestore.
-	 * 
-	 * @return The handle to the interface, as decorated by Spring.
-	 */
-	protected abstract DirectoryREST makeDirectoryInterface();
-
-	/**
-	 * Construct a RESTful interface to a run's input descriptors.
-	 * 
-	 * @return The handle to the interface, as decorated by Spring.
-	 */
-	protected abstract InputREST makeInputInterface();
-
-	/**
-	 * Construct a RESTful interface to a run's listeners.
-	 * 
-	 * @return The handle to the interface, as decorated by Spring.
-	 */
-	protected abstract ListenersREST makeListenersInterface();
-
-	/**
-	 * Construct a RESTful interface to a run's security.
-	 * 
-	 * @return The handle to the interface, as decorated by Spring.
-	 */
-	protected abstract RunSecurityREST makeSecurityInterface();
-
-	/**
-	 * Construct a RESTful interface to a run's interaction feed.
-	 * 
-	 * @return The handle to the interaface, as decorated by Spring.
-	 */
-	protected abstract InteractionFeed makeInteractionFeed();
-
-	@Override
-	@CallCounted
-	public Response runOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response workflowOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response profileOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response expiryOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response createTimeOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response startTimeOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response finishTimeOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response statusOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response outputOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response nameOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response stdoutOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response stderrOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response usageOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response logOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response runBundleOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response generateProvenanceOptions() {
-		return opt("PUT");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java
deleted file mode 100644
index 9dc69d7..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static java.util.UUID.randomUUID;
-import static javax.ws.rs.core.Response.created;
-import static javax.ws.rs.core.Response.noContent;
-import static org.taverna.server.master.common.Status.Initialized;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.net.URI;
-import java.util.Map;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.taverna.server.master.api.SecurityBean;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCredentialException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful interface to a single workflow run's security settings.
- * 
- * @author Donal Fellows
- */
-class RunSecurityREST implements TavernaServerSecurityREST, SecurityBean {
-	private TavernaServerSupport support;
-	private TavernaSecurityContext context;
-	private TavernaRun run;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	public RunSecurityREST connect(TavernaSecurityContext context,
-			TavernaRun run) {
-		this.context = context;
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Descriptor describe(UriInfo ui) {
-		return new Descriptor(secure(ui).path("{element}"), context.getOwner()
-				.getName(), context.getCredentials(), context.getTrusted());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String getOwner() {
-		return context.getOwner().getName();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public CredentialList listCredentials() {
-		return new CredentialList(context.getCredentials());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public CredentialHolder getParticularCredential(String id)
-			throws NoCredentialException {
-		for (Credential c : context.getCredentials())
-			if (c.id.equals(id))
-				return new CredentialHolder(c);
-		throw new NoCredentialException();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public CredentialHolder setParticularCredential(String id,
-			CredentialHolder cred, UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		Credential c = cred.credential;
-		c.id = id;
-		c.href = ui.getAbsolutePath().toString();
-		context.validateCredential(c);
-		context.deleteCredential(c);
-		context.addCredential(c);
-		return new CredentialHolder(c);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response addCredential(CredentialHolder cred, UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		Credential c = cred.credential;
-		c.id = randomUUID().toString();
-		URI uri = secure(ui).path("{id}").build(c.id);
-		c.href = uri.toString();
-		context.validateCredential(c);
-		context.addCredential(c);
-		return created(uri).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deleteAllCredentials(UriInfo ui)
-			throws BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		for (Credential c : context.getCredentials())
-			context.deleteCredential(c);
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deleteCredential(String id, UriInfo ui)
-			throws BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		context.deleteCredential(new Credential.Dummy(id));
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public TrustList listTrusted() {
-		return new TrustList(context.getTrusted());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Trust getParticularTrust(String id) throws NoCredentialException {
-		for (Trust t : context.getTrusted())
-			if (t.id.equals(id))
-				return t;
-		throw new NoCredentialException();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Trust setParticularTrust(String id, Trust t, UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		t.id = id;
-		t.href = ui.getAbsolutePath().toString();
-		context.validateTrusted(t);
-		context.deleteTrusted(t);
-		context.addTrusted(t);
-		return t;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response addTrust(Trust t, UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		t.id = randomUUID().toString();
-		URI uri = secure(ui).path("{id}").build(t.id);
-		t.href = uri.toString();
-		context.validateTrusted(t);
-		context.addTrusted(t);
-		return created(uri).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deleteAllTrusts(UriInfo ui) throws BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		for (Trust t : context.getTrusted())
-			context.deleteTrusted(t);
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deleteTrust(String id, UriInfo ui)
-			throws BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		Trust toDelete = new Trust();
-		toDelete.id = id;
-		context.deleteTrusted(toDelete);
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public PermissionsDescription describePermissions(UriInfo ui) {
-		Map<String, Permission> perm = support.getPermissionMap(context);
-		return new PermissionsDescription(secure(ui).path("{id}"), perm);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Permission describePermission(String id) {
-		return support.getPermission(context, id);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Permission setPermission(String id, Permission perm) {
-		support.setPermission(context, id, perm);
-		return support.getPermission(context, id);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deletePermission(String id, UriInfo ui) {
-		support.setPermission(context, id, Permission.None);
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response makePermission(PermissionDescription desc, UriInfo ui) {
-		support.setPermission(context, desc.userName, desc.permission);
-		return created(secure(ui).path("{user}").build(desc.userName)).build();
-	}
-
-	@Override
-	@CallCounted
-	public Response descriptionOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response ownerOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response credentialsOptions() {
-		return opt("POST", "DELETE");
-	}
-
-	@Override
-	@CallCounted
-	public Response credentialOptions(String id) {
-		return opt("PUT", "DELETE");
-	}
-
-	@Override
-	@CallCounted
-	public Response trustsOptions() {
-		return opt("POST", "DELETE");
-	}
-
-	@Override
-	@CallCounted
-	public Response trustOptions(String id) {
-		return opt("PUT", "DELETE");
-	}
-
-	@Override
-	@CallCounted
-	public Response permissionsOptions() {
-		return opt("POST");
-	}
-
-	@Override
-	@CallCounted
-	public Response permissionOptions(String id) {
-		return opt("PUT", "DELETE");
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java
deleted file mode 100644
index 2c841cc..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static java.util.Arrays.asList;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.util.List;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.taverna.server.master.api.OneListenerBean;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
-import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful interface to a single listener attached to a workflow run.
- * 
- * @author Donal Fellows
- */
-abstract class SingleListenerREST implements TavernaServerListenerREST,
-		OneListenerBean {
-	private Listener listen;
-	private TavernaRun run;
-
-	@Override
-	public SingleListenerREST connect(Listener listen, TavernaRun run) {
-		this.listen = listen;
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String getConfiguration() {
-		return listen.getConfiguration();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public ListenerDescription getDescription(UriInfo ui) {
-		return new ListenerDescription(listen, secure(ui));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public TavernaServerListenersREST.Properties getProperties(UriInfo ui) {
-		return new TavernaServerListenersREST.Properties(secure(ui).path(
-				"{prop}"), listen.listProperties());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public TavernaServerListenersREST.Property getProperty(
-			final String propertyName) throws NoListenerException {
-		List<String> p = asList(listen.listProperties());
-		if (p.contains(propertyName)) {
-			return makePropertyInterface().connect(listen, run, propertyName);
-		}
-		throw new NoListenerException("no such property");
-	}
-
-	protected abstract ListenerPropertyREST makePropertyInterface();
-
-	@Override
-	@CallCounted
-	public Response listenerOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response configurationOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response propertiesOptions() {
-		return opt();
-	}
-}


[05/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/JaxbSanityTest.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/JaxbSanityTest.java
new file mode 100644
index 0000000..79fc9bf
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/JaxbSanityTest.java
@@ -0,0 +1,370 @@
+/*
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Arrays;
+
+import javax.xml.bind.JAXBContext;
+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.master.admin.Admin;
+import org.taverna.server.master.common.Credential.KeyPair;
+import org.taverna.server.master.common.Credential.Password;
+import org.taverna.server.master.common.Capability;
+import org.taverna.server.master.common.DirEntryReference;
+import org.taverna.server.master.common.InputDescription;
+import org.taverna.server.master.common.Permission;
+import org.taverna.server.master.common.ProfileList;
+import org.taverna.server.master.common.RunReference;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.common.Uri;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.rest.DirectoryContents;
+import org.taverna.server.master.rest.ListenerDefinition;
+import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
+import org.taverna.server.master.rest.TavernaServerInputREST.InDesc;
+import org.taverna.server.master.rest.TavernaServerInputREST.InputsDescriptor;
+import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
+import org.taverna.server.master.rest.TavernaServerListenersREST.Listeners;
+import org.taverna.server.master.rest.TavernaServerListenersREST.Properties;
+import org.taverna.server.master.rest.TavernaServerListenersREST.PropertyDescription;
+import org.taverna.server.master.rest.TavernaServerREST.EnabledNotificationFabrics;
+import org.taverna.server.master.rest.TavernaServerREST.PermittedListeners;
+import org.taverna.server.master.rest.TavernaServerREST.PermittedWorkflows;
+import org.taverna.server.master.rest.TavernaServerREST.PolicyView.CapabilityList;
+import org.taverna.server.master.rest.TavernaServerREST.PolicyView.PolicyDescription;
+import org.taverna.server.master.rest.TavernaServerREST.RunList;
+import org.taverna.server.master.rest.TavernaServerREST.ServerDescription;
+import org.taverna.server.master.rest.TavernaServerRunREST.RunDescription;
+import org.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.taverna.server.master.rest.TavernaServerSecurityREST.CredentialHolder;
+import org.taverna.server.master.soap.DirEntry;
+import org.taverna.server.master.soap.FileContents;
+import org.taverna.server.master.soap.PermissionList;
+
+/**
+ * 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();
+	}
+
+	@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());
+	}
+
+	private boolean printSchema = false;
+
+	private void testJAXB(Class<?>... classes) throws Exception {
+		JAXBContext.newInstance(classes).generateSchema(sink);
+		if (printSchema)
+			System.out.println(schema());
+		assertTrue(schema().length() > 0);
+	}
+
+	@Test
+	public void testJAXBForDirEntryReference() throws Exception {
+		JAXBContext.newInstance(DirEntryReference.class).generateSchema(sink);
+		assertTrue(schema().length() > 0);
+	}
+
+	@Test
+	public void testJAXBForInputDescription() throws Exception {
+		testJAXB(InputDescription.class);
+	}
+
+	@Test
+	public void testJAXBForRunReference() throws Exception {
+		testJAXB(RunReference.class);
+	}
+
+	@Test
+	public void testJAXBForWorkflow() throws Exception {
+		testJAXB(Workflow.class);
+	}
+
+	@Test
+	public void testJAXBForStatus() throws Exception {
+		testJAXB(Status.class);
+	}
+
+	@Test
+	public void testJAXBForUri() throws Exception {
+		testJAXB(Uri.class);
+	}
+
+	@Test
+	public void testJAXBForDirectoryContents() throws Exception {
+		testJAXB(DirectoryContents.class);
+	}
+
+	@Test
+	public void testJAXBForListenerDefinition() throws Exception {
+		testJAXB(ListenerDefinition.class);
+	}
+
+	@Test
+	public void testJAXBForMakeOrUpdateDirEntry() throws Exception {
+		testJAXB(MakeOrUpdateDirEntry.class);
+	}
+
+	@Test
+	public void testJAXBForInDesc() throws Exception {
+		testJAXB(InDesc.class);
+	}
+
+	@Test
+	public void testJAXBForInputsDescriptor() throws Exception {
+		testJAXB(InputsDescriptor.class);
+	}
+
+	@Test
+	public void testJAXBForListenerDescription() throws Exception {
+		testJAXB(ListenerDescription.class);
+	}
+
+	@Test
+	public void testJAXBForListeners() throws Exception {
+		testJAXB(Listeners.class);
+	}
+
+	@Test
+	public void testJAXBForProperties() throws Exception {
+		testJAXB(Properties.class);
+	}
+
+	@Test
+	public void testJAXBForPropertyDescription() throws Exception {
+		testJAXB(PropertyDescription.class);
+	}
+
+	@Test
+	public void testJAXBForPermittedListeners() throws Exception {
+		testJAXB(PermittedListeners.class);
+	}
+
+	@Test
+	public void testJAXBForPermittedWorkflows() throws Exception {
+		testJAXB(PermittedWorkflows.class);
+	}
+
+	@Test
+	public void testJAXBForEnabledNotifiers() throws Exception {
+		testJAXB(EnabledNotificationFabrics.class);
+	}
+
+	@Test
+	public void testJAXBForServerDescription() throws Exception {
+		testJAXB(ServerDescription.class);
+	}
+
+	@Test
+	public void testJAXBForRunDescription() throws Exception {
+		testJAXB(RunDescription.class);
+	}
+
+	@Test
+	public void testJAXBForRunList() throws Exception {
+		testJAXB(RunList.class);
+	}
+
+	@Test
+	public void testJAXBForPolicyDescription() throws Exception {
+		testJAXB(PolicyDescription.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityCredential() throws Exception {
+		testJAXB(CredentialHolder.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityCredentialList() throws Exception {
+		testJAXB(TavernaServerSecurityREST.CredentialList.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityTrust() throws Exception {
+		testJAXB(Trust.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityTrustList() throws Exception {
+		testJAXB(TavernaServerSecurityREST.TrustList.class);
+	}
+
+	@Test
+	public void testJAXBForPermission() throws Exception {
+		testJAXB(Permission.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityPermissionDescription() throws Exception {
+		testJAXB(TavernaServerSecurityREST.PermissionDescription.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityPermissionsDescription() throws Exception {
+		testJAXB(TavernaServerSecurityREST.PermissionsDescription.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityDescriptor() throws Exception {
+		testJAXB(TavernaServerSecurityREST.Descriptor.class);
+	}
+
+	@Test
+	public void testJAXBForProfileList() throws Exception {
+		testJAXB(ProfileList.class);
+	}
+
+	@Test
+	public void testJAXBForDirEntry() throws Exception {
+		testJAXB(DirEntry.class);
+	}
+
+	@Test
+	public void testJAXBForCapability() throws Exception {
+		testJAXB(Capability.class);
+	}
+
+	@Test
+	public void testJAXBForCapabilityList() throws Exception {
+		testJAXB(CapabilityList.class);
+	}
+
+	@Test
+	public void testJAXBForEverythingREST() throws Exception {
+		testJAXB(DirEntryReference.class, InputDescription.class,
+				RunReference.class, Workflow.class, Status.class,
+				DirectoryContents.class, InDesc.class,
+				ListenerDefinition.class, MakeOrUpdateDirEntry.class,
+				InputsDescriptor.class, ListenerDescription.class,
+				Listeners.class, Properties.class, PropertyDescription.class,
+				PermittedListeners.class, PermittedWorkflows.class,
+				EnabledNotificationFabrics.class, ServerDescription.class,
+				RunDescription.class, Uri.class, RunList.class,
+				PolicyDescription.class, CredentialHolder.class, Trust.class,
+				TavernaServerSecurityREST.CredentialList.class,
+				TavernaServerSecurityREST.TrustList.class, Permission.class,
+				TavernaServerSecurityREST.Descriptor.class,
+				TavernaServerSecurityREST.PermissionDescription.class,
+				TavernaServerSecurityREST.PermissionsDescription.class,
+				ProfileList.class, Capability.class, CapabilityList.class);
+	}
+
+	@Test
+	public void testJAXBForEverythingSOAP() throws Exception {
+		testJAXB(DirEntry.class, FileContents.class, InputDescription.class,
+				Permission.class, PermissionList.class,
+				PermissionList.SinglePermissionMapping.class,
+				RunReference.class, Status.class, Trust.class, Uri.class,
+				ProfileList.class, Workflow.class, Capability.class);
+	}
+
+	@Test
+	public void testUserPassSerializeDeserialize() throws Exception {
+		JAXBContext c = JAXBContext.newInstance(CredentialHolder.class);
+
+		Password password = new Password();
+		password.username = "foo";
+		password.password = "bar";
+
+		// Serialize
+		StringWriter sw = new StringWriter();
+		CredentialHolder credIn = new CredentialHolder(password);
+		c.createMarshaller().marshal(credIn, sw);
+
+		// Deserialize
+		StringReader sr = new StringReader(sw.toString());
+		Object credOutObj = c.createUnmarshaller().unmarshal(sr);
+
+		// Test value-equivalence
+		assertEquals(credIn.getClass(), credOutObj.getClass());
+		CredentialHolder credOut = (CredentialHolder) credOutObj;
+		assertEquals(credIn.credential.getClass(),
+				credOut.credential.getClass());
+		assertEquals(credIn.getUserpass().username,
+				credOut.getUserpass().username);
+		assertEquals(credIn.getUserpass().password,
+				credOut.getUserpass().password);
+	}
+
+	@Test
+	public void testKeypairSerializeDeserialize() throws Exception {
+		JAXBContext c = JAXBContext.newInstance(CredentialHolder.class);
+
+		KeyPair keypair = new KeyPair();
+		keypair.credentialName = "foo";
+		keypair.credentialBytes = new byte[] { 1, 2, 3 };
+
+		// Serialize
+		StringWriter sw = new StringWriter();
+		CredentialHolder credIn = new CredentialHolder(keypair);
+		c.createMarshaller().marshal(credIn, sw);
+
+		// Deserialize
+		StringReader sr = new StringReader(sw.toString());
+		Object credOutObj = c.createUnmarshaller().unmarshal(sr);
+
+		// Test value-equivalence
+		assertEquals(credIn.getClass(), credOutObj.getClass());
+		CredentialHolder credOut = (CredentialHolder) credOutObj;
+		assertEquals(credIn.credential.getClass(),
+				credOut.credential.getClass());
+		assertEquals(credIn.getKeypair().credentialName,
+				credOut.getKeypair().credentialName);
+		assertTrue(Arrays.equals(credIn.getKeypair().credentialBytes,
+				credOut.getKeypair().credentialBytes));
+	}
+
+	@Test
+	public void testJAXBforAdmininstration() throws Exception {
+		testJAXB(Admin.AdminDescription.class);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/TavernaServerImplTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/TavernaServerImplTest.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/TavernaServerImplTest.java
new file mode 100644
index 0000000..b1191f1
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/TavernaServerImplTest.java
@@ -0,0 +1,262 @@
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonMap;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.taverna.server.master.api.ManagementModel;
+import org.taverna.server.master.common.RunReference;
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.mocks.ExampleRun;
+import org.taverna.server.master.mocks.MockPolicy;
+import org.taverna.server.master.mocks.SimpleListenerFactory;
+import org.taverna.server.master.mocks.SimpleNonpersistentRunStore;
+
+public class TavernaServerImplTest {
+	private TavernaServer server;
+	private MockPolicy policy;
+	private SimpleNonpersistentRunStore store;
+	@java.lang.SuppressWarnings("unused")
+	private ExampleRun.Builder runFactory;
+	private SimpleListenerFactory lFactory;
+	private TavernaServerSupport support;
+
+	private String lrunname;
+	private String lrunconf;
+
+	Listener makeListener(TavernaRun run, final String config) {
+		lrunname = run.toString();
+		lrunconf = config;
+		return new Listener() {
+			@Override
+			public String getConfiguration() {
+				return config;
+			}
+
+			@Override
+			public String getName() {
+				return "bar";
+			}
+
+			@Override
+			public String getProperty(String propName)
+					throws NoListenerException {
+				throw new NoListenerException();
+			}
+
+			@Override
+			public String getType() {
+				return "foo";
+			}
+
+			@Override
+			public String[] listProperties() {
+				return new String[0];
+			}
+
+			@Override
+			public void setProperty(String propName, String value)
+					throws NoListenerException, BadPropertyValueException {
+				throw new NoListenerException();
+			}
+		};
+	}
+
+	@Before
+	public void wireup() throws Exception {
+		// Wire everything up; ought to be done with Spring, but this works...
+		server = new TavernaServer() {
+			@Override
+			protected RunREST makeRunInterface() {
+				return new RunREST() {
+					@Override
+					protected ListenersREST makeListenersInterface() {
+						return new ListenersREST() {
+							@Override
+							protected SingleListenerREST makeListenerInterface() {
+								return new SingleListenerREST() {
+									@Override
+									protected ListenerPropertyREST makePropertyInterface() {
+										return new ListenerPropertyREST() {
+										};
+									}
+								};
+							}
+						};
+					}
+
+					@Override
+					protected RunSecurityREST makeSecurityInterface() {
+						return new RunSecurityREST() {
+						};
+					}
+
+					@Override
+					protected DirectoryREST makeDirectoryInterface() {
+						return new DirectoryREST() {
+						};
+					}
+
+					@Override
+					protected InputREST makeInputInterface() {
+						return new InputREST() {
+						};
+					}
+
+					@Override
+					protected InteractionFeed makeInteractionFeed() {
+						return null; // TODO...
+					}
+				};
+			}
+
+			@Override
+			public PolicyView getPolicyDescription() {
+				return new PolicyREST();
+			}
+		};
+		support = new TavernaServerSupport();
+		server.setSupport(support);
+		support.setWebapp(server);
+		support.setLogGetPrincipalFailures(false);
+		support.setStateModel(new ManagementModel() {
+			@Override
+			public boolean getAllowNewWorkflowRuns() {
+				return true;
+			}
+
+			@Override
+			public boolean getLogIncomingWorkflows() {
+				return false;
+			}
+
+			@Override
+			public boolean getLogOutgoingExceptions() {
+				return false;
+			}
+
+			@Override
+			public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
+			}
+
+			@Override
+			public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
+			}
+
+			@Override
+			public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
+			}
+
+			@Override
+			public String getUsageRecordLogFile() {
+				return null;
+			}
+
+			@Override
+			public void setUsageRecordLogFile(String usageRecordLogFile) {
+			}
+		});
+		server.setPolicy(policy = new MockPolicy());
+		support.setPolicy(policy);
+		server.setRunStore(store = new SimpleNonpersistentRunStore());
+		support.setRunStore(store);
+		store.setPolicy(policy);
+		support.setRunFactory(runFactory = new ExampleRun.Builder(1));
+		support.setListenerFactory(lFactory = new SimpleListenerFactory());
+		lFactory.setBuilders(singletonMap(
+				"foo",
+				(SimpleListenerFactory.Builder) new SimpleListenerFactory.Builder() {
+					@Override
+					public Listener build(TavernaRun run, String configuration)
+							throws NoListenerException {
+						return makeListener(run, configuration);
+					}
+				}));
+	}
+
+	@Test
+	public void defaults1() {
+		assertNotNull(server);
+	}
+
+	@Test
+	public void defaults2() {
+		assertEquals(10, server.getServerMaxRuns());
+	}
+
+	@Test
+	public void defaults3() {
+		assertEquals(1, server.getServerListeners().length);
+	}
+
+	@Test
+	public void defaults4() {
+		assertNotNull(support.getPrincipal());
+	}
+
+	@Test
+	public void serverAsksPolicyForMaxRuns() {
+		int oldmax = policy.maxruns;
+		try {
+			policy.maxruns = 1;
+			assertEquals(1, server.getServerMaxRuns());
+		} finally {
+			policy.maxruns = oldmax;
+		}
+	}
+
+	@Test
+	public void makeAndKillARun() throws NoUpdateException, UnknownRunException {
+		RunReference rr = server.submitWorkflow(null);
+		assertNotNull(rr);
+		assertNotNull(rr.name);
+		server.destroyRun(rr.name);
+	}
+
+	@Test
+	public void makeListenKillRun() throws Exception {
+		RunReference run = server.submitWorkflow(null);
+		try {
+			lrunname = lrunconf = null;
+			assertEquals(asList("foo"), asList(server.getServerListeners()));
+			String l = server.addRunListener(run.name, "foo", "foobar");
+			assertEquals("bar", l);
+			assertEquals("foobar", lrunconf);
+			assertEquals(lrunname, support.getRun(run.name).toString());
+			assertEquals(asList("default", "bar"),
+					asList(server.getRunListeners(run.name)));
+			assertEquals(0,
+					server.getRunListenerProperties(run.name, "bar").length);
+		} finally {
+			try {
+				server.destroyRun(run.name);
+			} catch (Exception e) {
+				// Ignore
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/WorkflowSerializationTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/WorkflowSerializationTest.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/WorkflowSerializationTest.java
new file mode 100644
index 0000000..1217c1f
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/WorkflowSerializationTest.java
@@ -0,0 +1,84 @@
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.taverna.server.master.common.Workflow;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class WorkflowSerializationTest {
+	@Test
+	public void testWorkflowSerialization()
+			throws ParserConfigurationException, IOException,
+			ClassNotFoundException {
+		DocumentBuilder db = DocumentBuilderFactory.newInstance()
+				.newDocumentBuilder();
+		Document doc = db.getDOMImplementation().createDocument(null, null,
+				null);
+		Element workflow = doc.createElementNS(T2FLOW_NS, T2FLOW_ROOTNAME);
+		Element foo = doc.createElementNS("urn:foo:bar", "pqr:foo");
+		foo.setTextContent("bar");
+		foo.setAttribute("xyz", "abc");
+		workflow.appendChild(foo);
+		Workflow w = new Workflow(workflow);
+
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+			oos.writeObject(w);
+		}
+
+		Object o;
+		try (ObjectInputStream ois = new ObjectInputStream(
+				new ByteArrayInputStream(baos.toByteArray()))) {
+			o = ois.readObject();
+		}
+
+		Assert.assertNotNull(o);
+		Assert.assertEquals(w.getClass(), o.getClass());
+		Workflow w2 = (Workflow) o;
+		Assert.assertNotNull(w2.getT2flowWorkflow());
+		Element e = w2.getT2flowWorkflow();
+		Assert.assertEquals(T2FLOW_ROOTNAME, e.getLocalName());
+		Assert.assertEquals(T2FLOW_NS, e.getNamespaceURI());
+		e = (Element) e.getFirstChild();
+		Assert.assertEquals("foo", e.getLocalName());
+		Assert.assertEquals("pqr", e.getPrefix());
+		Assert.assertEquals("urn:foo:bar", e.getNamespaceURI());
+		Assert.assertEquals("bar", e.getTextContent());
+		Assert.assertEquals(1, e.getChildNodes().getLength());
+		// WARNING: These are dependent on how namespaces are encoded!
+		Assert.assertEquals(2, e.getAttributes().getLength());
+		Assert.assertEquals("xyz", ((Attr) e.getAttributes().item(1)).getLocalName());
+		Assert.assertEquals("abc", e.getAttribute("xyz"));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/ExampleRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/ExampleRun.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/ExampleRun.java
new file mode 100644
index 0000000..862cf2c
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/ExampleRun.java
@@ -0,0 +1,465 @@
+/*
+ */
+package org.taverna.server.master.mocks;
+/*
+ * 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.
+ */
+
+import static java.util.Calendar.MINUTE;
+import static java.util.Collections.unmodifiableList;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.common.Status.Initialized;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.xml.ws.handler.MessageContext;
+
+import org.springframework.security.core.context.SecurityContext;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.factories.RunFactory;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.Input;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.SecurityContextFactory;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+@SuppressWarnings("serial")
+public class ExampleRun implements TavernaRun, TavernaSecurityContext {
+	String id;
+	List<Listener> listeners;
+	Workflow workflow;
+	Status status;
+	Date expiry;
+	UsernamePrincipal owner;
+	String inputBaclava;
+	String outputBaclava;
+	java.io.File realRoot;
+	List<Input> inputs;
+	String name;
+
+	public ExampleRun(UsernamePrincipal creator, Workflow workflow, Date expiry) {
+		this.id = randomUUID().toString();
+		this.listeners = new ArrayList<>();
+		this.status = Initialized;
+		this.owner = creator;
+		this.workflow = workflow;
+		this.expiry = expiry;
+		this.inputs = new ArrayList<>();
+		listeners.add(new DefaultListener());
+	}
+
+	@Override
+	public void addListener(Listener l) {
+		listeners.add(l);
+	}
+
+	@Override
+	public void destroy() {
+		// This does nothing...
+	}
+
+	@Override
+	public Date getExpiry() {
+		return expiry;
+	}
+
+	@Override
+	public List<Listener> getListeners() {
+		return listeners;
+	}
+
+	@Override
+	public TavernaSecurityContext getSecurityContext() {
+		return this;
+	}
+
+	@Override
+	public Status getStatus() {
+		return status;
+	}
+
+	@Override
+	public Workflow getWorkflow() {
+		return workflow;
+	}
+
+	@Override
+	public Directory getWorkingDirectory() {
+		// LATER: Implement this!
+		throw new UnsupportedOperationException("not yet implemented");
+	}
+
+	@Override
+	public void setExpiry(Date d) {
+		if (d.after(new Date()))
+			this.expiry = d;
+	}
+
+	@Override
+	public String setStatus(Status s) {
+		this.status = s;
+		return null;
+	}
+
+	@Override
+	public UsernamePrincipal getOwner() {
+		return owner;
+	}
+
+	public static class Builder implements RunFactory {
+		private int lifetime;
+
+		public Builder(int initialLifetimeMinutes) {
+			this.lifetime = initialLifetimeMinutes;
+		}
+
+		@Override
+		public TavernaRun create(UsernamePrincipal creator, Workflow workflow) {
+			Calendar c = GregorianCalendar.getInstance();
+			c.add(MINUTE, lifetime);
+			return new ExampleRun(creator, workflow, c.getTime());
+		}
+
+		@Override
+		public boolean isAllowingRunsToStart() {
+			return true;
+		}
+	}
+
+	static final String[] emptyArray = new String[0];
+
+	class DefaultListener implements Listener {
+		@Override
+		public String getConfiguration() {
+			return "";
+		}
+
+		@Override
+		public String getName() {
+			return "default";
+		}
+
+		@Override
+		public String getType() {
+			return "default";
+		}
+
+		@Override
+		public String[] listProperties() {
+			return emptyArray;
+		}
+
+		@Override
+		public String getProperty(String propName) throws NoListenerException {
+			throw new NoListenerException("no such property");
+		}
+
+		@Override
+		public void setProperty(String propName, String value)
+				throws NoListenerException {
+			throw new NoListenerException("no such property");
+		}
+	}
+
+	@Override
+	public String getInputBaclavaFile() {
+		return inputBaclava;
+	}
+
+	@Override
+	public List<Input> getInputs() {
+		return unmodifiableList(inputs);
+	}
+
+	@Override
+	public String getOutputBaclavaFile() {
+		return outputBaclava;
+	}
+
+	class ExampleInput implements Input {
+		public String name;
+		public String file;
+		public String value;
+		public String delim;
+
+		public ExampleInput(String name) {
+			this.name = name;
+		}
+
+		@Override
+		public String getFile() {
+			return file;
+		}
+
+		@Override
+		public String getName() {
+			return name;
+		}
+
+		@Override
+		public String getValue() {
+			return value;
+		}
+
+		@Override
+		public void setFile(String file) throws FilesystemAccessException,
+				BadStateChangeException {
+			if (status != Status.Initialized)
+				throw new BadStateChangeException();
+			checkBadFilename(file);
+			this.file = file;
+			this.value = null;
+			inputBaclava = null;
+		}
+
+		@Override
+		public void setValue(String value) throws BadStateChangeException {
+			if (status != Status.Initialized)
+				throw new BadStateChangeException();
+			this.value = value;
+			this.file = null;
+			inputBaclava = null;
+		}
+
+		void reset() {
+			this.file = null;
+			this.value = null;
+		}
+
+		@Override
+		public String getDelimiter() {
+			return delim;
+		}
+
+		@Override
+		public void setDelimiter(String delimiter)
+				throws BadStateChangeException {
+			if (status != Status.Initialized)
+				throw new BadStateChangeException();
+			if (delimiter == null)
+				delim = null;
+			else
+				delim = delimiter.substring(0, 1);
+		}
+	}
+
+	@Override
+	public Input makeInput(String name) throws BadStateChangeException {
+		if (status != Status.Initialized)
+			throw new BadStateChangeException();
+		Input i = new ExampleInput(name);
+		inputs.add(i);
+		return i;
+	}
+
+	static void checkBadFilename(String filename)
+			throws FilesystemAccessException {
+		if (filename.startsWith("/"))
+			throw new FilesystemAccessException("filename may not be absolute");
+		if (Arrays.asList(filename.split("/")).contains(".."))
+			throw new FilesystemAccessException(
+					"filename may not refer to parent");
+	}
+
+	@Override
+	public void setInputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException {
+		if (status != Status.Initialized)
+			throw new BadStateChangeException();
+		checkBadFilename(filename);
+		inputBaclava = filename;
+		for (Input i : inputs)
+			((ExampleInput) i).reset();
+	}
+
+	@Override
+	public void setOutputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException {
+		if (status != Status.Initialized)
+			throw new BadStateChangeException();
+		if (filename != null)
+			checkBadFilename(filename);
+		outputBaclava = filename;
+	}
+
+	private Date created = new Date();
+	@Override
+	public Date getCreationTimestamp() {
+		return created;
+	}
+
+	@Override
+	public Date getFinishTimestamp() {
+		return null;
+	}
+
+	@Override
+	public Date getStartTimestamp() {
+		return null;
+	}
+
+	@Override
+	public Credential[] getCredentials() {
+		return new Credential[0];
+	}
+
+	@Override
+	public void addCredential(Credential toAdd) {
+	}
+
+	@Override
+	public void deleteCredential(Credential toDelete) {
+	}
+
+	@Override
+	public Trust[] getTrusted() {
+		return new Trust[0];
+	}
+
+	@Override
+	public void addTrusted(Trust toAdd) {
+	}
+
+	@Override
+	public void deleteTrusted(Trust toDelete) {
+	}
+
+	@Override
+	public void validateCredential(Credential c)
+			throws InvalidCredentialException {
+	}
+
+	@Override
+	public void validateTrusted(Trust t) throws InvalidCredentialException {
+	}
+
+	@Override
+	public void initializeSecurityFromSOAPContext(MessageContext context) {
+		// Do nothing
+	}
+
+	@Override
+	public void initializeSecurityFromRESTContext(HttpHeaders headers) {
+		// Do nothing
+	}
+
+	@Override
+	public void conveySecurity() throws GeneralSecurityException, IOException {
+		// Do nothing
+	}
+
+	@Override
+	public SecurityContextFactory getFactory() {
+		return null;
+	}
+
+	private Set<String> destroyers = new HashSet<String>();
+	private Set<String> updaters = new HashSet<String>();
+	private Set<String> readers = new HashSet<String>();
+	@Override
+	public Set<String> getPermittedDestroyers() {
+		return destroyers;
+	}
+
+	@Override
+	public void setPermittedDestroyers(Set<String> destroyers) {
+		this.destroyers = destroyers;
+		updaters.addAll(destroyers);
+		readers.addAll(destroyers);
+	}
+
+	@Override
+	public Set<String> getPermittedUpdaters() {
+		return updaters;
+	}
+
+	@Override
+	public void setPermittedUpdaters(Set<String> updaters) {
+		this.updaters = updaters;
+		this.updaters.addAll(destroyers);
+		readers.addAll(updaters);
+	}
+
+	@Override
+	public Set<String> getPermittedReaders() {
+		return readers;
+	}
+
+	@Override
+	public void setPermittedReaders(Set<String> readers) {
+		this.readers = readers;
+		this.readers.addAll(destroyers);
+		this.readers.addAll(updaters);
+	}
+
+	@Override
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public void initializeSecurityFromContext(SecurityContext securityContext)
+			throws Exception {
+		// Do nothing
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public void setName(String name) {
+		this.name = (name.length() > 5 ? name.substring(0, 5) : name);
+	}
+
+	@Override
+	public void ping() throws UnknownRunException {
+		// Do nothing
+	}
+
+	@Override
+	public boolean getGenerateProvenance() {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean generateProvenance) {
+		// TODO Auto-generated method stub
+		
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/MockPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/MockPolicy.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/MockPolicy.java
new file mode 100644
index 0000000..b61fc10
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/MockPolicy.java
@@ -0,0 +1,75 @@
+package org.taverna.server.master.mocks;
+/*
+ * 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.
+ */
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+public class MockPolicy extends SimpleServerPolicy {
+	public MockPolicy() {
+		super();
+		super.setCleanerInterval(30);
+	}
+
+	public int maxruns = 10;
+	Integer usermaxruns;
+	Set<TavernaRun> denyaccess = new HashSet<>();
+	boolean exnOnUpdate, exnOnCreate, exnOnDelete;
+
+	@Override
+	public int getMaxRuns() {
+		return maxruns;
+	}
+
+	@Override
+	public Integer getMaxRuns(UsernamePrincipal user) {
+		return usermaxruns;
+	}
+
+	@Override
+	public boolean permitAccess(UsernamePrincipal user, TavernaRun run) {
+		return !denyaccess.contains(run);
+	}
+
+	@Override
+	public void permitCreate(UsernamePrincipal user, Workflow workflow)
+			throws NoCreateException {
+		if (this.exnOnCreate)
+			throw new NoCreateException();
+	}
+
+	@Override
+	public void permitDestroy(UsernamePrincipal user, TavernaRun run)
+			throws NoDestroyException {
+		if (this.exnOnDelete)
+			throw new NoDestroyException();
+	}
+
+	@Override
+	public void permitUpdate(UsernamePrincipal user, TavernaRun run)
+			throws NoUpdateException {
+		if (this.exnOnUpdate)
+			throw new NoUpdateException();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleListenerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleListenerFactory.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleListenerFactory.java
new file mode 100644
index 0000000..7d9c998
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleListenerFactory.java
@@ -0,0 +1,80 @@
+package org.taverna.server.master.mocks;
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.factories.ListenerFactory;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * A factory for event listener. The factory is configured using Spring.
+ * 
+ * @author Donal Fellows
+ */
+public class SimpleListenerFactory implements ListenerFactory {
+	private Map<String, Builder> builders = new HashMap<>();
+
+	public void setBuilders(Map<String, Builder> builders) {
+		this.builders = builders;
+	}
+
+	@Override
+	public List<String> getSupportedListenerTypes() {
+		return new ArrayList<>(builders.keySet());
+	}
+
+	@Override
+	public Listener makeListener(TavernaRun run, String listenerType,
+			String configuration) throws NoListenerException {
+		Builder b = builders.get(listenerType);
+		if (b == null)
+			throw new NoListenerException("no such listener type");
+		Listener l = b.build(run, configuration);
+		run.addListener(l);
+		return l;
+	}
+
+	/**
+	 * How to actually construct a listener.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public interface Builder {
+		/**
+		 * Make an event listener attached to a run.
+		 * 
+		 * @param run
+		 *            The run to attach to.
+		 * @param configuration
+		 *            A user-specified configuration document. The constructed
+		 *            listener <i>should</i> process this configuration document
+		 *            and be able to return it to the user when requested.
+		 * @return The listener object.
+		 * @throws NoListenerException
+		 *             If the listener construction failed or the
+		 *             <b>configuration</b> document was bad in some way.
+		 */
+		public Listener build(TavernaRun run, String configuration)
+				throws NoListenerException;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleNonpersistentRunStore.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
new file mode 100644
index 0000000..63b6754
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
@@ -0,0 +1,167 @@
+package org.taverna.server.master.mocks;
+/*
+ * 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.
+ */
+
+import java.lang.ref.WeakReference;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.RunStore;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Example of a store for Taverna Workflow Runs.
+ * 
+ * @author Donal Fellows
+ */
+public class SimpleNonpersistentRunStore implements RunStore {
+	private Map<String, TavernaRun> store = new HashMap<>();
+	private Object lock = new Object();
+
+	Timer timer;
+	private CleanerTask cleaner;
+
+	/**
+	 * The connection to the main policy store. Suitable for wiring up with
+	 * Spring.
+	 * 
+	 * @param p
+	 *            The policy to connect to.
+	 */
+	public void setPolicy(SimpleServerPolicy p) {
+		p.store = this;
+		cleanerIntervalUpdated(p.getCleanerInterval());
+	}
+
+	public SimpleNonpersistentRunStore() {
+		timer = new Timer("SimpleNonpersistentRunStore.CleanerTimer", true);
+		cleanerIntervalUpdated(300);
+	}
+
+	@Override
+	protected void finalize() {
+		timer.cancel();
+	}
+
+	/**
+	 * Remove and destroy all runs that are expired at the moment that this
+	 * method starts.
+	 */
+	void clean() {
+		Date now = new Date();
+		synchronized (lock) {
+			// Use an iterator so we have access to its remove() method...
+			Iterator<TavernaRun> i = store.values().iterator();
+			while (i.hasNext()) {
+				TavernaRun w = i.next();
+				if (w.getExpiry().before(now)) {
+					i.remove();
+					try {
+						w.destroy();
+					} catch (NoDestroyException e) {
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Reconfigure the cleaner task's call interval. This is called internally
+	 * and from the Policy when the interval is set there.
+	 * 
+	 * @param intervalInSeconds
+	 *            How long between runs of the cleaner task, in seconds.
+	 */
+	void cleanerIntervalUpdated(int intervalInSeconds) {
+		if (cleaner != null)
+			cleaner.cancel();
+		cleaner = new CleanerTask(this, intervalInSeconds);
+	}
+
+	@Override
+	public TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
+			throws UnknownRunException {
+		synchronized (lock) {
+			TavernaRun w = store.get(uuid);
+			if (w == null || !p.permitAccess(user, w))
+				throw new UnknownRunException();
+			return w;
+		}
+	}
+
+	@Override
+	public TavernaRun getRun(String uuid) throws UnknownRunException {
+		synchronized (lock) {
+			TavernaRun w = store.get(uuid);
+			if (w == null)
+				throw new UnknownRunException();
+			return w;
+		}
+	}
+
+	@Override
+	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
+		Map<String, TavernaRun> filtered = new HashMap<>();
+		synchronized (lock) {
+			for (Map.Entry<String, TavernaRun> entry : store.entrySet())
+				if (p.permitAccess(user, entry.getValue()))
+					filtered.put(entry.getKey(), entry.getValue());
+		}
+		return filtered;
+	}
+
+	@Override
+	public String registerRun(TavernaRun run) {
+		synchronized (lock) {
+			store.put(run.getId(), run);
+			return run.getId();
+		}
+	}
+
+	@Override
+	public void unregisterRun(String uuid) {
+		synchronized (lock) {
+			store.remove(uuid);
+		}
+	}
+}
+
+class CleanerTask extends TimerTask {
+	WeakReference<SimpleNonpersistentRunStore> store;
+
+	CleanerTask(SimpleNonpersistentRunStore store, int interval) {
+		this.store = new WeakReference<>(store);
+		int tms = interval * 1000;
+		store.timer.scheduleAtFixedRate(this, tms, tms);
+	}
+
+	@Override
+	public void run() {
+		SimpleNonpersistentRunStore s = store.get();
+		if (s != null) {
+			s.clean();
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleServerPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleServerPolicy.java b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleServerPolicy.java
new file mode 100644
index 0000000..8dd2757
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/apache/taverna/server/master/mocks/SimpleServerPolicy.java
@@ -0,0 +1,126 @@
+package org.taverna.server.master.mocks;
+/*
+ * 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.
+ */
+
+import java.net.URI;
+import java.util.List;
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A very simple (and unsafe) security model. The number of runs is configurable
+ * through Spring (or 10 if unconfigured) with no per-user limits supported, all
+ * workflows are permitted, and all identified users may create a workflow run.
+ * Any user may read off information about any run, but only its owner may
+ * modify or destroy it.
+ * <p>
+ * Note that this is a <i>Policy Enforcement Point</i> for access control to
+ * individual workflows.
+ * 
+ * @author Donal Fellows
+ */
+public class SimpleServerPolicy implements Policy {
+	private int maxRuns = 10;
+	private int cleanerInterval;
+	SimpleNonpersistentRunStore store;
+
+	public void setMaxRuns(int maxRuns) {
+		this.maxRuns = maxRuns;
+	}
+
+	@Override
+	public int getMaxRuns() {
+		return maxRuns;
+	}
+
+	@Override
+	public Integer getMaxRuns(UsernamePrincipal p) {
+		return null; // No per-user limits
+	}
+
+	public int getCleanerInterval() {
+		return cleanerInterval;
+	}
+
+	/**
+	 * Sets how often the store of workflow runs will try to clean out expired
+	 * runs.
+	 * 
+	 * @param intervalInSeconds
+	 */
+	public void setCleanerInterval(int intervalInSeconds) {
+		cleanerInterval = intervalInSeconds;
+		if (store != null)
+			store.cleanerIntervalUpdated(intervalInSeconds);
+	}
+
+	@Override
+	public boolean permitAccess(UsernamePrincipal p, TavernaRun run) {
+		// No secrets here!
+		return true;
+	}
+
+	@Override
+	public void permitCreate(UsernamePrincipal p, Workflow workflow)
+			throws NoCreateException {
+		// Only identified users may create
+		if (p == null)
+			throw new NoCreateException();
+		// Global run count limit enforcement
+		if (store.listRuns(p, this).size() >= maxRuns)
+			throw new NoCreateException();
+		// Per-user run count enforcement would come here
+	}
+
+	@Override
+	public void permitDestroy(UsernamePrincipal p, TavernaRun run)
+			throws NoDestroyException {
+		// Only the creator may destroy
+		if (p == null || !p.equals(run.getSecurityContext().getOwner()))
+			throw new NoDestroyException();
+	}
+
+	@Override
+	public void permitUpdate(UsernamePrincipal p, TavernaRun run)
+			throws NoUpdateException {
+		// Only the creator may change
+		if (p == null || !p.equals(run.getSecurityContext().getOwner()))
+			throw new NoUpdateException();
+	}
+
+	@Override
+	public int getOperatingLimit() {
+		return 1;
+	}
+
+	@Override
+	public List<URI> listPermittedWorkflowURIs(UsernamePrincipal user) {
+		return null;
+	}
+
+	@Override
+	public void setPermittedWorkflowURIs(UsernamePrincipal user,
+			List<URI> permitted) {
+		// Ignore
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
deleted file mode 100644
index 79fc9bf..0000000
--- a/taverna-server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- */
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.Arrays;
-
-import javax.xml.bind.JAXBContext;
-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.master.admin.Admin;
-import org.taverna.server.master.common.Credential.KeyPair;
-import org.taverna.server.master.common.Credential.Password;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.common.InputDescription;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.rest.DirectoryContents;
-import org.taverna.server.master.rest.ListenerDefinition;
-import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
-import org.taverna.server.master.rest.TavernaServerInputREST.InDesc;
-import org.taverna.server.master.rest.TavernaServerInputREST.InputsDescriptor;
-import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
-import org.taverna.server.master.rest.TavernaServerListenersREST.Listeners;
-import org.taverna.server.master.rest.TavernaServerListenersREST.Properties;
-import org.taverna.server.master.rest.TavernaServerListenersREST.PropertyDescription;
-import org.taverna.server.master.rest.TavernaServerREST.EnabledNotificationFabrics;
-import org.taverna.server.master.rest.TavernaServerREST.PermittedListeners;
-import org.taverna.server.master.rest.TavernaServerREST.PermittedWorkflows;
-import org.taverna.server.master.rest.TavernaServerREST.PolicyView.CapabilityList;
-import org.taverna.server.master.rest.TavernaServerREST.PolicyView.PolicyDescription;
-import org.taverna.server.master.rest.TavernaServerREST.RunList;
-import org.taverna.server.master.rest.TavernaServerREST.ServerDescription;
-import org.taverna.server.master.rest.TavernaServerRunREST.RunDescription;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-import org.taverna.server.master.rest.TavernaServerSecurityREST.CredentialHolder;
-import org.taverna.server.master.soap.DirEntry;
-import org.taverna.server.master.soap.FileContents;
-import org.taverna.server.master.soap.PermissionList;
-
-/**
- * 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();
-	}
-
-	@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());
-	}
-
-	private boolean printSchema = false;
-
-	private void testJAXB(Class<?>... classes) throws Exception {
-		JAXBContext.newInstance(classes).generateSchema(sink);
-		if (printSchema)
-			System.out.println(schema());
-		assertTrue(schema().length() > 0);
-	}
-
-	@Test
-	public void testJAXBForDirEntryReference() throws Exception {
-		JAXBContext.newInstance(DirEntryReference.class).generateSchema(sink);
-		assertTrue(schema().length() > 0);
-	}
-
-	@Test
-	public void testJAXBForInputDescription() throws Exception {
-		testJAXB(InputDescription.class);
-	}
-
-	@Test
-	public void testJAXBForRunReference() throws Exception {
-		testJAXB(RunReference.class);
-	}
-
-	@Test
-	public void testJAXBForWorkflow() throws Exception {
-		testJAXB(Workflow.class);
-	}
-
-	@Test
-	public void testJAXBForStatus() throws Exception {
-		testJAXB(Status.class);
-	}
-
-	@Test
-	public void testJAXBForUri() throws Exception {
-		testJAXB(Uri.class);
-	}
-
-	@Test
-	public void testJAXBForDirectoryContents() throws Exception {
-		testJAXB(DirectoryContents.class);
-	}
-
-	@Test
-	public void testJAXBForListenerDefinition() throws Exception {
-		testJAXB(ListenerDefinition.class);
-	}
-
-	@Test
-	public void testJAXBForMakeOrUpdateDirEntry() throws Exception {
-		testJAXB(MakeOrUpdateDirEntry.class);
-	}
-
-	@Test
-	public void testJAXBForInDesc() throws Exception {
-		testJAXB(InDesc.class);
-	}
-
-	@Test
-	public void testJAXBForInputsDescriptor() throws Exception {
-		testJAXB(InputsDescriptor.class);
-	}
-
-	@Test
-	public void testJAXBForListenerDescription() throws Exception {
-		testJAXB(ListenerDescription.class);
-	}
-
-	@Test
-	public void testJAXBForListeners() throws Exception {
-		testJAXB(Listeners.class);
-	}
-
-	@Test
-	public void testJAXBForProperties() throws Exception {
-		testJAXB(Properties.class);
-	}
-
-	@Test
-	public void testJAXBForPropertyDescription() throws Exception {
-		testJAXB(PropertyDescription.class);
-	}
-
-	@Test
-	public void testJAXBForPermittedListeners() throws Exception {
-		testJAXB(PermittedListeners.class);
-	}
-
-	@Test
-	public void testJAXBForPermittedWorkflows() throws Exception {
-		testJAXB(PermittedWorkflows.class);
-	}
-
-	@Test
-	public void testJAXBForEnabledNotifiers() throws Exception {
-		testJAXB(EnabledNotificationFabrics.class);
-	}
-
-	@Test
-	public void testJAXBForServerDescription() throws Exception {
-		testJAXB(ServerDescription.class);
-	}
-
-	@Test
-	public void testJAXBForRunDescription() throws Exception {
-		testJAXB(RunDescription.class);
-	}
-
-	@Test
-	public void testJAXBForRunList() throws Exception {
-		testJAXB(RunList.class);
-	}
-
-	@Test
-	public void testJAXBForPolicyDescription() throws Exception {
-		testJAXB(PolicyDescription.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityCredential() throws Exception {
-		testJAXB(CredentialHolder.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityCredentialList() throws Exception {
-		testJAXB(TavernaServerSecurityREST.CredentialList.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityTrust() throws Exception {
-		testJAXB(Trust.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityTrustList() throws Exception {
-		testJAXB(TavernaServerSecurityREST.TrustList.class);
-	}
-
-	@Test
-	public void testJAXBForPermission() throws Exception {
-		testJAXB(Permission.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityPermissionDescription() throws Exception {
-		testJAXB(TavernaServerSecurityREST.PermissionDescription.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityPermissionsDescription() throws Exception {
-		testJAXB(TavernaServerSecurityREST.PermissionsDescription.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityDescriptor() throws Exception {
-		testJAXB(TavernaServerSecurityREST.Descriptor.class);
-	}
-
-	@Test
-	public void testJAXBForProfileList() throws Exception {
-		testJAXB(ProfileList.class);
-	}
-
-	@Test
-	public void testJAXBForDirEntry() throws Exception {
-		testJAXB(DirEntry.class);
-	}
-
-	@Test
-	public void testJAXBForCapability() throws Exception {
-		testJAXB(Capability.class);
-	}
-
-	@Test
-	public void testJAXBForCapabilityList() throws Exception {
-		testJAXB(CapabilityList.class);
-	}
-
-	@Test
-	public void testJAXBForEverythingREST() throws Exception {
-		testJAXB(DirEntryReference.class, InputDescription.class,
-				RunReference.class, Workflow.class, Status.class,
-				DirectoryContents.class, InDesc.class,
-				ListenerDefinition.class, MakeOrUpdateDirEntry.class,
-				InputsDescriptor.class, ListenerDescription.class,
-				Listeners.class, Properties.class, PropertyDescription.class,
-				PermittedListeners.class, PermittedWorkflows.class,
-				EnabledNotificationFabrics.class, ServerDescription.class,
-				RunDescription.class, Uri.class, RunList.class,
-				PolicyDescription.class, CredentialHolder.class, Trust.class,
-				TavernaServerSecurityREST.CredentialList.class,
-				TavernaServerSecurityREST.TrustList.class, Permission.class,
-				TavernaServerSecurityREST.Descriptor.class,
-				TavernaServerSecurityREST.PermissionDescription.class,
-				TavernaServerSecurityREST.PermissionsDescription.class,
-				ProfileList.class, Capability.class, CapabilityList.class);
-	}
-
-	@Test
-	public void testJAXBForEverythingSOAP() throws Exception {
-		testJAXB(DirEntry.class, FileContents.class, InputDescription.class,
-				Permission.class, PermissionList.class,
-				PermissionList.SinglePermissionMapping.class,
-				RunReference.class, Status.class, Trust.class, Uri.class,
-				ProfileList.class, Workflow.class, Capability.class);
-	}
-
-	@Test
-	public void testUserPassSerializeDeserialize() throws Exception {
-		JAXBContext c = JAXBContext.newInstance(CredentialHolder.class);
-
-		Password password = new Password();
-		password.username = "foo";
-		password.password = "bar";
-
-		// Serialize
-		StringWriter sw = new StringWriter();
-		CredentialHolder credIn = new CredentialHolder(password);
-		c.createMarshaller().marshal(credIn, sw);
-
-		// Deserialize
-		StringReader sr = new StringReader(sw.toString());
-		Object credOutObj = c.createUnmarshaller().unmarshal(sr);
-
-		// Test value-equivalence
-		assertEquals(credIn.getClass(), credOutObj.getClass());
-		CredentialHolder credOut = (CredentialHolder) credOutObj;
-		assertEquals(credIn.credential.getClass(),
-				credOut.credential.getClass());
-		assertEquals(credIn.getUserpass().username,
-				credOut.getUserpass().username);
-		assertEquals(credIn.getUserpass().password,
-				credOut.getUserpass().password);
-	}
-
-	@Test
-	public void testKeypairSerializeDeserialize() throws Exception {
-		JAXBContext c = JAXBContext.newInstance(CredentialHolder.class);
-
-		KeyPair keypair = new KeyPair();
-		keypair.credentialName = "foo";
-		keypair.credentialBytes = new byte[] { 1, 2, 3 };
-
-		// Serialize
-		StringWriter sw = new StringWriter();
-		CredentialHolder credIn = new CredentialHolder(keypair);
-		c.createMarshaller().marshal(credIn, sw);
-
-		// Deserialize
-		StringReader sr = new StringReader(sw.toString());
-		Object credOutObj = c.createUnmarshaller().unmarshal(sr);
-
-		// Test value-equivalence
-		assertEquals(credIn.getClass(), credOutObj.getClass());
-		CredentialHolder credOut = (CredentialHolder) credOutObj;
-		assertEquals(credIn.credential.getClass(),
-				credOut.credential.getClass());
-		assertEquals(credIn.getKeypair().credentialName,
-				credOut.getKeypair().credentialName);
-		assertTrue(Arrays.equals(credIn.getKeypair().credentialBytes,
-				credOut.getKeypair().credentialBytes));
-	}
-
-	@Test
-	public void testJAXBforAdmininstration() throws Exception {
-		testJAXB(Admin.AdminDescription.class);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
deleted file mode 100644
index b1191f1..0000000
--- a/taverna-server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
+++ /dev/null
@@ -1,262 +0,0 @@
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonMap;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.mocks.ExampleRun;
-import org.taverna.server.master.mocks.MockPolicy;
-import org.taverna.server.master.mocks.SimpleListenerFactory;
-import org.taverna.server.master.mocks.SimpleNonpersistentRunStore;
-
-public class TavernaServerImplTest {
-	private TavernaServer server;
-	private MockPolicy policy;
-	private SimpleNonpersistentRunStore store;
-	@java.lang.SuppressWarnings("unused")
-	private ExampleRun.Builder runFactory;
-	private SimpleListenerFactory lFactory;
-	private TavernaServerSupport support;
-
-	private String lrunname;
-	private String lrunconf;
-
-	Listener makeListener(TavernaRun run, final String config) {
-		lrunname = run.toString();
-		lrunconf = config;
-		return new Listener() {
-			@Override
-			public String getConfiguration() {
-				return config;
-			}
-
-			@Override
-			public String getName() {
-				return "bar";
-			}
-
-			@Override
-			public String getProperty(String propName)
-					throws NoListenerException {
-				throw new NoListenerException();
-			}
-
-			@Override
-			public String getType() {
-				return "foo";
-			}
-
-			@Override
-			public String[] listProperties() {
-				return new String[0];
-			}
-
-			@Override
-			public void setProperty(String propName, String value)
-					throws NoListenerException, BadPropertyValueException {
-				throw new NoListenerException();
-			}
-		};
-	}
-
-	@Before
-	public void wireup() throws Exception {
-		// Wire everything up; ought to be done with Spring, but this works...
-		server = new TavernaServer() {
-			@Override
-			protected RunREST makeRunInterface() {
-				return new RunREST() {
-					@Override
-					protected ListenersREST makeListenersInterface() {
-						return new ListenersREST() {
-							@Override
-							protected SingleListenerREST makeListenerInterface() {
-								return new SingleListenerREST() {
-									@Override
-									protected ListenerPropertyREST makePropertyInterface() {
-										return new ListenerPropertyREST() {
-										};
-									}
-								};
-							}
-						};
-					}
-
-					@Override
-					protected RunSecurityREST makeSecurityInterface() {
-						return new RunSecurityREST() {
-						};
-					}
-
-					@Override
-					protected DirectoryREST makeDirectoryInterface() {
-						return new DirectoryREST() {
-						};
-					}
-
-					@Override
-					protected InputREST makeInputInterface() {
-						return new InputREST() {
-						};
-					}
-
-					@Override
-					protected InteractionFeed makeInteractionFeed() {
-						return null; // TODO...
-					}
-				};
-			}
-
-			@Override
-			public PolicyView getPolicyDescription() {
-				return new PolicyREST();
-			}
-		};
-		support = new TavernaServerSupport();
-		server.setSupport(support);
-		support.setWebapp(server);
-		support.setLogGetPrincipalFailures(false);
-		support.setStateModel(new ManagementModel() {
-			@Override
-			public boolean getAllowNewWorkflowRuns() {
-				return true;
-			}
-
-			@Override
-			public boolean getLogIncomingWorkflows() {
-				return false;
-			}
-
-			@Override
-			public boolean getLogOutgoingExceptions() {
-				return false;
-			}
-
-			@Override
-			public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
-			}
-
-			@Override
-			public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
-			}
-
-			@Override
-			public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
-			}
-
-			@Override
-			public String getUsageRecordLogFile() {
-				return null;
-			}
-
-			@Override
-			public void setUsageRecordLogFile(String usageRecordLogFile) {
-			}
-		});
-		server.setPolicy(policy = new MockPolicy());
-		support.setPolicy(policy);
-		server.setRunStore(store = new SimpleNonpersistentRunStore());
-		support.setRunStore(store);
-		store.setPolicy(policy);
-		support.setRunFactory(runFactory = new ExampleRun.Builder(1));
-		support.setListenerFactory(lFactory = new SimpleListenerFactory());
-		lFactory.setBuilders(singletonMap(
-				"foo",
-				(SimpleListenerFactory.Builder) new SimpleListenerFactory.Builder() {
-					@Override
-					public Listener build(TavernaRun run, String configuration)
-							throws NoListenerException {
-						return makeListener(run, configuration);
-					}
-				}));
-	}
-
-	@Test
-	public void defaults1() {
-		assertNotNull(server);
-	}
-
-	@Test
-	public void defaults2() {
-		assertEquals(10, server.getServerMaxRuns());
-	}
-
-	@Test
-	public void defaults3() {
-		assertEquals(1, server.getServerListeners().length);
-	}
-
-	@Test
-	public void defaults4() {
-		assertNotNull(support.getPrincipal());
-	}
-
-	@Test
-	public void serverAsksPolicyForMaxRuns() {
-		int oldmax = policy.maxruns;
-		try {
-			policy.maxruns = 1;
-			assertEquals(1, server.getServerMaxRuns());
-		} finally {
-			policy.maxruns = oldmax;
-		}
-	}
-
-	@Test
-	public void makeAndKillARun() throws NoUpdateException, UnknownRunException {
-		RunReference rr = server.submitWorkflow(null);
-		assertNotNull(rr);
-		assertNotNull(rr.name);
-		server.destroyRun(rr.name);
-	}
-
-	@Test
-	public void makeListenKillRun() throws Exception {
-		RunReference run = server.submitWorkflow(null);
-		try {
-			lrunname = lrunconf = null;
-			assertEquals(asList("foo"), asList(server.getServerListeners()));
-			String l = server.addRunListener(run.name, "foo", "foobar");
-			assertEquals("bar", l);
-			assertEquals("foobar", lrunconf);
-			assertEquals(lrunname, support.getRun(run.name).toString());
-			assertEquals(asList("default", "bar"),
-					asList(server.getRunListeners(run.name)));
-			assertEquals(0,
-					server.getRunListenerProperties(run.name, "bar").length);
-		} finally {
-			try {
-				server.destroyRun(run.name);
-			} catch (Exception e) {
-				// Ignore
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
deleted file mode 100644
index 1217c1f..0000000
--- a/taverna-server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.taverna.server.master;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.taverna.server.master.common.Workflow;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class WorkflowSerializationTest {
-	@Test
-	public void testWorkflowSerialization()
-			throws ParserConfigurationException, IOException,
-			ClassNotFoundException {
-		DocumentBuilder db = DocumentBuilderFactory.newInstance()
-				.newDocumentBuilder();
-		Document doc = db.getDOMImplementation().createDocument(null, null,
-				null);
-		Element workflow = doc.createElementNS(T2FLOW_NS, T2FLOW_ROOTNAME);
-		Element foo = doc.createElementNS("urn:foo:bar", "pqr:foo");
-		foo.setTextContent("bar");
-		foo.setAttribute("xyz", "abc");
-		workflow.appendChild(foo);
-		Workflow w = new Workflow(workflow);
-
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
-			oos.writeObject(w);
-		}
-
-		Object o;
-		try (ObjectInputStream ois = new ObjectInputStream(
-				new ByteArrayInputStream(baos.toByteArray()))) {
-			o = ois.readObject();
-		}
-
-		Assert.assertNotNull(o);
-		Assert.assertEquals(w.getClass(), o.getClass());
-		Workflow w2 = (Workflow) o;
-		Assert.assertNotNull(w2.getT2flowWorkflow());
-		Element e = w2.getT2flowWorkflow();
-		Assert.assertEquals(T2FLOW_ROOTNAME, e.getLocalName());
-		Assert.assertEquals(T2FLOW_NS, e.getNamespaceURI());
-		e = (Element) e.getFirstChild();
-		Assert.assertEquals("foo", e.getLocalName());
-		Assert.assertEquals("pqr", e.getPrefix());
-		Assert.assertEquals("urn:foo:bar", e.getNamespaceURI());
-		Assert.assertEquals("bar", e.getTextContent());
-		Assert.assertEquals(1, e.getChildNodes().getLength());
-		// WARNING: These are dependent on how namespaces are encoded!
-		Assert.assertEquals(2, e.getAttributes().getLength());
-		Assert.assertEquals("xyz", ((Attr) e.getAttributes().item(1)).getLocalName());
-		Assert.assertEquals("abc", e.getAttribute("xyz"));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
deleted file mode 100644
index 862cf2c..0000000
--- a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- */
-package org.taverna.server.master.mocks;
-/*
- * 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.
- */
-
-import static java.util.Calendar.MINUTE;
-import static java.util.Collections.unmodifiableList;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.common.Status.Initialized;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.ws.rs.core.HttpHeaders;
-import javax.xml.ws.handler.MessageContext;
-
-import org.springframework.security.core.context.SecurityContext;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.factories.RunFactory;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-@SuppressWarnings("serial")
-public class ExampleRun implements TavernaRun, TavernaSecurityContext {
-	String id;
-	List<Listener> listeners;
-	Workflow workflow;
-	Status status;
-	Date expiry;
-	UsernamePrincipal owner;
-	String inputBaclava;
-	String outputBaclava;
-	java.io.File realRoot;
-	List<Input> inputs;
-	String name;
-
-	public ExampleRun(UsernamePrincipal creator, Workflow workflow, Date expiry) {
-		this.id = randomUUID().toString();
-		this.listeners = new ArrayList<>();
-		this.status = Initialized;
-		this.owner = creator;
-		this.workflow = workflow;
-		this.expiry = expiry;
-		this.inputs = new ArrayList<>();
-		listeners.add(new DefaultListener());
-	}
-
-	@Override
-	public void addListener(Listener l) {
-		listeners.add(l);
-	}
-
-	@Override
-	public void destroy() {
-		// This does nothing...
-	}
-
-	@Override
-	public Date getExpiry() {
-		return expiry;
-	}
-
-	@Override
-	public List<Listener> getListeners() {
-		return listeners;
-	}
-
-	@Override
-	public TavernaSecurityContext getSecurityContext() {
-		return this;
-	}
-
-	@Override
-	public Status getStatus() {
-		return status;
-	}
-
-	@Override
-	public Workflow getWorkflow() {
-		return workflow;
-	}
-
-	@Override
-	public Directory getWorkingDirectory() {
-		// LATER: Implement this!
-		throw new UnsupportedOperationException("not yet implemented");
-	}
-
-	@Override
-	public void setExpiry(Date d) {
-		if (d.after(new Date()))
-			this.expiry = d;
-	}
-
-	@Override
-	public String setStatus(Status s) {
-		this.status = s;
-		return null;
-	}
-
-	@Override
-	public UsernamePrincipal getOwner() {
-		return owner;
-	}
-
-	public static class Builder implements RunFactory {
-		private int lifetime;
-
-		public Builder(int initialLifetimeMinutes) {
-			this.lifetime = initialLifetimeMinutes;
-		}
-
-		@Override
-		public TavernaRun create(UsernamePrincipal creator, Workflow workflow) {
-			Calendar c = GregorianCalendar.getInstance();
-			c.add(MINUTE, lifetime);
-			return new ExampleRun(creator, workflow, c.getTime());
-		}
-
-		@Override
-		public boolean isAllowingRunsToStart() {
-			return true;
-		}
-	}
-
-	static final String[] emptyArray = new String[0];
-
-	class DefaultListener implements Listener {
-		@Override
-		public String getConfiguration() {
-			return "";
-		}
-
-		@Override
-		public String getName() {
-			return "default";
-		}
-
-		@Override
-		public String getType() {
-			return "default";
-		}
-
-		@Override
-		public String[] listProperties() {
-			return emptyArray;
-		}
-
-		@Override
-		public String getProperty(String propName) throws NoListenerException {
-			throw new NoListenerException("no such property");
-		}
-
-		@Override
-		public void setProperty(String propName, String value)
-				throws NoListenerException {
-			throw new NoListenerException("no such property");
-		}
-	}
-
-	@Override
-	public String getInputBaclavaFile() {
-		return inputBaclava;
-	}
-
-	@Override
-	public List<Input> getInputs() {
-		return unmodifiableList(inputs);
-	}
-
-	@Override
-	public String getOutputBaclavaFile() {
-		return outputBaclava;
-	}
-
-	class ExampleInput implements Input {
-		public String name;
-		public String file;
-		public String value;
-		public String delim;
-
-		public ExampleInput(String name) {
-			this.name = name;
-		}
-
-		@Override
-		public String getFile() {
-			return file;
-		}
-
-		@Override
-		public String getName() {
-			return name;
-		}
-
-		@Override
-		public String getValue() {
-			return value;
-		}
-
-		@Override
-		public void setFile(String file) throws FilesystemAccessException,
-				BadStateChangeException {
-			if (status != Status.Initialized)
-				throw new BadStateChangeException();
-			checkBadFilename(file);
-			this.file = file;
-			this.value = null;
-			inputBaclava = null;
-		}
-
-		@Override
-		public void setValue(String value) throws BadStateChangeException {
-			if (status != Status.Initialized)
-				throw new BadStateChangeException();
-			this.value = value;
-			this.file = null;
-			inputBaclava = null;
-		}
-
-		void reset() {
-			this.file = null;
-			this.value = null;
-		}
-
-		@Override
-		public String getDelimiter() {
-			return delim;
-		}
-
-		@Override
-		public void setDelimiter(String delimiter)
-				throws BadStateChangeException {
-			if (status != Status.Initialized)
-				throw new BadStateChangeException();
-			if (delimiter == null)
-				delim = null;
-			else
-				delim = delimiter.substring(0, 1);
-		}
-	}
-
-	@Override
-	public Input makeInput(String name) throws BadStateChangeException {
-		if (status != Status.Initialized)
-			throw new BadStateChangeException();
-		Input i = new ExampleInput(name);
-		inputs.add(i);
-		return i;
-	}
-
-	static void checkBadFilename(String filename)
-			throws FilesystemAccessException {
-		if (filename.startsWith("/"))
-			throw new FilesystemAccessException("filename may not be absolute");
-		if (Arrays.asList(filename.split("/")).contains(".."))
-			throw new FilesystemAccessException(
-					"filename may not refer to parent");
-	}
-
-	@Override
-	public void setInputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException {
-		if (status != Status.Initialized)
-			throw new BadStateChangeException();
-		checkBadFilename(filename);
-		inputBaclava = filename;
-		for (Input i : inputs)
-			((ExampleInput) i).reset();
-	}
-
-	@Override
-	public void setOutputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException {
-		if (status != Status.Initialized)
-			throw new BadStateChangeException();
-		if (filename != null)
-			checkBadFilename(filename);
-		outputBaclava = filename;
-	}
-
-	private Date created = new Date();
-	@Override
-	public Date getCreationTimestamp() {
-		return created;
-	}
-
-	@Override
-	public Date getFinishTimestamp() {
-		return null;
-	}
-
-	@Override
-	public Date getStartTimestamp() {
-		return null;
-	}
-
-	@Override
-	public Credential[] getCredentials() {
-		return new Credential[0];
-	}
-
-	@Override
-	public void addCredential(Credential toAdd) {
-	}
-
-	@Override
-	public void deleteCredential(Credential toDelete) {
-	}
-
-	@Override
-	public Trust[] getTrusted() {
-		return new Trust[0];
-	}
-
-	@Override
-	public void addTrusted(Trust toAdd) {
-	}
-
-	@Override
-	public void deleteTrusted(Trust toDelete) {
-	}
-
-	@Override
-	public void validateCredential(Credential c)
-			throws InvalidCredentialException {
-	}
-
-	@Override
-	public void validateTrusted(Trust t) throws InvalidCredentialException {
-	}
-
-	@Override
-	public void initializeSecurityFromSOAPContext(MessageContext context) {
-		// Do nothing
-	}
-
-	@Override
-	public void initializeSecurityFromRESTContext(HttpHeaders headers) {
-		// Do nothing
-	}
-
-	@Override
-	public void conveySecurity() throws GeneralSecurityException, IOException {
-		// Do nothing
-	}
-
-	@Override
-	public SecurityContextFactory getFactory() {
-		return null;
-	}
-
-	private Set<String> destroyers = new HashSet<String>();
-	private Set<String> updaters = new HashSet<String>();
-	private Set<String> readers = new HashSet<String>();
-	@Override
-	public Set<String> getPermittedDestroyers() {
-		return destroyers;
-	}
-
-	@Override
-	public void setPermittedDestroyers(Set<String> destroyers) {
-		this.destroyers = destroyers;
-		updaters.addAll(destroyers);
-		readers.addAll(destroyers);
-	}
-
-	@Override
-	public Set<String> getPermittedUpdaters() {
-		return updaters;
-	}
-
-	@Override
-	public void setPermittedUpdaters(Set<String> updaters) {
-		this.updaters = updaters;
-		this.updaters.addAll(destroyers);
-		readers.addAll(updaters);
-	}
-
-	@Override
-	public Set<String> getPermittedReaders() {
-		return readers;
-	}
-
-	@Override
-	public void setPermittedReaders(Set<String> readers) {
-		this.readers = readers;
-		this.readers.addAll(destroyers);
-		this.readers.addAll(updaters);
-	}
-
-	@Override
-	public String getId() {
-		return id;
-	}
-
-	@Override
-	public void initializeSecurityFromContext(SecurityContext securityContext)
-			throws Exception {
-		// Do nothing
-	}
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	@Override
-	public void setName(String name) {
-		this.name = (name.length() > 5 ? name.substring(0, 5) : name);
-	}
-
-	@Override
-	public void ping() throws UnknownRunException {
-		// Do nothing
-	}
-
-	@Override
-	public boolean getGenerateProvenance() {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean generateProvenance) {
-		// TODO Auto-generated method stub
-		
-	}
-}



[11/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java
deleted file mode 100644
index e554997..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.TEXT;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Listener;
-
-/**
- * This represents <i>all</i> the event listeners attached to a workflow run.
- * 
- * @author Donal Fellows
- * @see TavernaServerListenerREST
- */
-@RolesAllowed(USER)
-@Description("This represents all the event listeners attached to a workflow "
-		+ "run.")
-public interface TavernaServerListenersREST {
-	/**
-	 * Get the listeners installed in the workflow run.
-	 * 
-	 * @param ui
-	 *            About how this method was called.
-	 * @return A list of descriptions of listeners.
-	 */
-	@GET
-	@Path("/")
-	@Produces({ XML, JSON })
-	@Description("Get the listeners installed in the workflow run.")
-	@Nonnull
-	Listeners getDescription(@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Add a new event listener to the named workflow run.
-	 * 
-	 * @param typeAndConfiguration
-	 *            What type of run should be created, and how should it be
-	 *            configured.
-	 * @param ui
-	 *            About how this method was called.
-	 * @return An HTTP response to the creation request.
-	 * @throws NoUpdateException
-	 *             If the user is not permitted to update the run.
-	 * @throws NoListenerException
-	 *             If no listener with the given type exists, or if the
-	 *             configuration is unacceptable in some way.
-	 */
-	@POST
-	@Path("/")
-	@Consumes({ XML, JSON })
-	@Description("Add a new event listener to the named workflow run.")
-	@Nonnull
-	Response addListener(@Nonnull ListenerDefinition typeAndConfiguration,
-			@Nonnull @Context UriInfo ui) throws NoUpdateException,
-			NoListenerException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path("/")
-	@Description("Produces the description of the run listeners' operations.")
-	Response listenersOptions();
-
-	/**
-	 * Resolve a particular listener from its name.
-	 * 
-	 * @param name
-	 *            The name of the listener to look up.
-	 * @return The listener's delegate in the REST world.
-	 * @throws NoListenerException
-	 *             If no listener with the given name exists.
-	 */
-	@Path("{name}")
-	@Description("Resolve a particular listener from its name.")
-	@Nonnull
-	TavernaServerListenerREST getListener(
-			@Nonnull @PathParam("name") String name) throws NoListenerException;
-
-	/**
-	 * This represents a single event listener attached to a workflow run.
-	 * 
-	 * @author Donal Fellows
-	 * @see TavernaServerListenersREST
-	 * @see Property
-	 */
-	@RolesAllowed(USER)
-	@Description("This represents a single event listener attached to a "
-			+ "workflow run.")
-	public interface TavernaServerListenerREST {
-		/**
-		 * Get the description of this listener.
-		 * 
-		 * @param ui
-		 *            Information about this request.
-		 * @return A description document.
-		 */
-		@GET
-		@Path("/")
-		@Produces({ XML, JSON })
-		@Description("Get the description of this listener.")
-		@Nonnull
-		ListenerDescription getDescription(@Nonnull @Context UriInfo ui);
-
-		/** Get an outline of the operations supported. */
-		@OPTIONS
-		@Path("/")
-		@Description("Produces the description of one run listener's operations.")
-		Response listenerOptions();
-
-		/**
-		 * Get the configuration for the given event listener that is attached
-		 * to a workflow run.
-		 * 
-		 * @return The configuration of the listener.
-		 */
-		@GET
-		@Path("configuration")
-		@Produces(TEXT)
-		@Description("Get the configuration for the given event listener that "
-				+ "is attached to a workflow run.")
-		@Nonnull
-		String getConfiguration();
-
-		/** Get an outline of the operations supported. */
-		@OPTIONS
-		@Path("configuration")
-		@Description("Produces the description of one run listener's "
-				+ "configuration's operations.")
-		Response configurationOptions();
-
-		/**
-		 * Get the list of properties supported by a given event listener
-		 * attached to a workflow run.
-		 * 
-		 * @param ui
-		 *            Information about this request.
-		 * @return The list of property names.
-		 */
-		@GET
-		@Path("properties")
-		@Produces({ XML, JSON })
-		@Description("Get the list of properties supported by a given event "
-				+ "listener attached to a workflow run.")
-		@Nonnull
-		Properties getProperties(@Nonnull @Context UriInfo ui);
-
-		/** Get an outline of the operations supported. */
-		@OPTIONS
-		@Path("properties")
-		@Description("Produces the description of one run listener's "
-				+ "properties' operations.")
-		Response propertiesOptions();
-
-		/**
-		 * Get an object representing a particular property.
-		 * 
-		 * @param propertyName
-		 * @return The property delegate.
-		 * @throws NoListenerException
-		 *             If there is no such property.
-		 */
-		@Path("properties/{propertyName}")
-		@Description("Get an object representing a particular property.")
-		@Nonnull
-		Property getProperty(
-				@Nonnull @PathParam("propertyName") String propertyName)
-				throws NoListenerException;
-	}
-
-	/**
-	 * This represents a single property attached of an event listener.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@RolesAllowed(USER)
-	@Description("This represents a single property attached of an event "
-			+ "listener.")
-	public interface Property {
-		/**
-		 * Get the value of the particular property of an event listener
-		 * attached to a workflow run.
-		 * 
-		 * @return The value of the property.
-		 */
-		@GET
-		@Path("/")
-		@Produces(TEXT)
-		@Description("Get the value of the particular property of an event "
-				+ "listener attached to a workflow run.")
-		@Nonnull
-		String getValue();
-
-		/**
-		 * Set the value of the particular property of an event listener
-		 * attached to a workflow run. Changing the value of the property may
-		 * cause the listener to alter its behaviour significantly.
-		 * 
-		 * @param value
-		 *            The value to set the property to.
-		 * @return The value of the property after being set.
-		 * @throws NoUpdateException
-		 *             If the user is not permitted to update the run.
-		 * @throws NoListenerException
-		 *             If the property is in the wrong format.
-		 */
-		@PUT
-		@Path("/")
-		@Consumes(TEXT)
-		@Produces(TEXT)
-		@Description("Set the value of the particular property of an event "
-				+ "listener attached to a workflow run.")
-		@Nonnull
-		String setValue(@Nonnull String value) throws NoUpdateException,
-				NoListenerException;
-
-		/** Get an outline of the operations supported. */
-		@OPTIONS
-		@Path("/")
-		@Description("Produces the description of one run listener's "
-				+ "property's operations.")
-		Response options();
-	}
-
-	/**
-	 * A description of an event listener that is attached to a workflow run.
-	 * Done with JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "ListenerDescription")
-	public class ListenerDescription extends VersionedElement {
-		/** Where this listener is located. */
-		@XmlAttribute(name = "href", namespace = XLINK)
-		@XmlSchemaType(name = "anyURI")
-		public URI location;
-		/** The (arbitrary) name of the event listener. */
-		@XmlAttribute
-		public String name;
-		/** The type of the event listener. */
-		@XmlAttribute
-		public String type;
-		/**
-		 * The location of the configuration document for the event listener.
-		 */
-		public Uri configuration;
-		/**
-		 * The name and location of the properties supported by the event
-		 * listener.
-		 */
-		@XmlElementWrapper(name = "properties", nillable = false)
-		@XmlElement(name = "property", nillable = false)
-		public List<PropertyDescription> properties;
-
-		/**
-		 * Make a blank listener description.
-		 */
-		public ListenerDescription() {
-		}
-
-		/**
-		 * Make a listener description that characterizes the given listener.
-		 * 
-		 * @param listener
-		 *            The listener to describe.
-		 * @param ub
-		 *            The factory for URIs. Must have already been secured.
-		 */
-		public ListenerDescription(Listener listener, UriBuilder ub) {
-			super(true);
-			name = listener.getName();
-			type = listener.getType();
-			configuration = new Uri(ub.clone().path("configuration"));
-			UriBuilder ub2 = ub.clone().path("properties/{prop}");
-			String[] props = listener.listProperties();
-			properties = new ArrayList<>(props.length);
-			for (String propName : props)
-				properties.add(new PropertyDescription(propName, ub2));
-		}
-	}
-
-	/**
-	 * The description of a single property, done with JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlType(name = "PropertyDescription")
-	public static class PropertyDescription extends Uri {
-		/**
-		 * The name of the property.
-		 */
-		@XmlAttribute
-		String name;
-
-		/**
-		 * Make an empty description of a property.
-		 */
-		public PropertyDescription() {
-		}
-
-		/**
-		 * Make a description of a property.
-		 * 
-		 * @param listenerName
-		 *            The name of the listener whose property this is.
-		 * @param propName
-		 *            The name of the property.
-		 * @param ub
-		 *            The factory for URIs. Must have already been secured.
-		 */
-		PropertyDescription(String propName, UriBuilder ub) {
-			super(ub, propName);
-			this.name = propName;
-		}
-	}
-
-	/**
-	 * The list of descriptions of listeners attached to a run. Done with JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "")
-	public static class Listeners extends VersionedElement {
-		/**
-		 * The listeners for a workflow run.
-		 */
-		@XmlElement(name = "listener")
-		public List<ListenerDescription> listener;
-
-		/**
-		 * Make a blank description of listeners.
-		 */
-		public Listeners() {
-			listener = new ArrayList<>();
-		}
-
-		/**
-		 * Make a description of the whole group out of the given list of
-		 * listener descriptions.
-		 * 
-		 * @param listeners
-		 *            The collection of (partial) listener descriptions.
-		 * @param ub
-		 *            How to build the location of the listeners. Must have
-		 *            already been secured.
-		 */
-		public Listeners(List<ListenerDescription> listeners, UriBuilder ub) {
-			super(true);
-			listener = listeners;
-			for (ListenerDescription ld : listeners)
-				ld.location = ub.build(ld.name);
-		}
-	}
-
-	/**
-	 * The list of properties of a listener. Done with JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "")
-	public static class Properties extends VersionedElement {
-		/**
-		 * The references to the properties of a listener.
-		 */
-		@XmlElement
-		public List<PropertyDescription> property;
-
-		/**
-		 * Make an empty description of the properties of a listener.
-		 */
-		public Properties() {
-		}
-
-		/**
-		 * Make the description of the properties of a listener.
-		 * 
-		 * @param ub
-		 *            The factory for URIs, configured. Must have already been
-		 *            secured.
-		 * @param properties
-		 *            The names of the properties.
-		 */
-		public Properties(UriBuilder ub, String[] properties) {
-			super(true);
-			property = new ArrayList<>(properties.length);
-			for (String propName : properties)
-				property.add(new PropertyDescription(propName, ub));
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java
deleted file mode 100644
index 161b017..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.URI_LIST;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_CAPABILITIES;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_NOTIFIERS;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_OP_LIMIT;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_PERM_LIST;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_PERM_WF;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_RUN_LIMIT;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.ROOT;
-import static org.taverna.server.master.rest.TavernaServerREST.PathNames.RUNS;
-import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.model.Feed;
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.common.Capability;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.soap.TavernaServerSOAP;
-
-/**
- * The REST service interface to Taverna 3 Server.
- * 
- * @author Donal Fellows
- * @see TavernaServerSOAP
- */
-@RolesAllowed(USER)
-@Description("This is REST service interface to Taverna " + Version.JAVA
-		+ " Server.")
-public interface TavernaServerREST {
-	/**
-	 * Produces the description of the service.
-	 * 
-	 * @param ui
-	 *            About the URI being accessed.
-	 * @return The description.
-	 */
-	@GET
-	@Path(ROOT)
-	@Produces({ XML, JSON })
-	@Description("Produces the description of the service.")
-	@Nonnull
-	ServerDescription describeService(@Nonnull @Context UriInfo ui);
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ROOT)
-	@Description("Produces the description of the service.")
-	Response serviceOptions();
-
-	/**
-	 * Produces a description of the list of runs.
-	 * 
-	 * @param ui
-	 *            About the URI being accessed.
-	 * @return A description of the list of runs that are available.
-	 */
-	@GET
-	@Path(RUNS)
-	@Produces({ XML, JSON })
-	@RolesAllowed(USER)
-	@Description("Produces a list of all runs visible to the user.")
-	@Nonnull
-	RunList listUsersRuns(@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Accepts (or not) a request to create a new run executing the given
-	 * workflow.
-	 * 
-	 * @param workflow
-	 *            The workflow document to execute.
-	 * @param ui
-	 *            About the URI being accessed.
-	 * @return A response to the POST describing what was created.
-	 * @throws NoUpdateException
-	 *             If the POST failed.
-	 */
-	@POST
-	@Path(RUNS)
-	@Consumes({ T2FLOW, SCUFL2, XML })
-	@RolesAllowed(USER)
-	@Description("Accepts (or not) a request to create a new run executing "
-			+ "the given workflow.")
-	@Nonnull
-	Response submitWorkflow(@Nonnull Workflow workflow,
-			@Nonnull @Context UriInfo ui) throws NoUpdateException;
-
-	/**
-	 * Accepts (or not) a request to create a new run executing the workflow at
-	 * the given location.
-	 * 
-	 * @param workflowReference
-	 *            The wrapped URI to workflow document to execute.
-	 * @param ui
-	 *            About the URI being POSTed to.
-	 * @return A response to the POST describing what was created.
-	 * @throws NoUpdateException
-	 *             If the POST failed.
-	 * @throw NoCreateException If the workflow couldn't be read into the server
-	 *        or the engine rejects it.
-	 */
-	@POST
-	@Path(RUNS)
-	@Consumes(URI_LIST)
-	@RolesAllowed(USER)
-	@Description("Accepts a URL to a workflow to download and run. The URL "
-			+ "must be hosted on a publicly-accessible service.")
-	@Nonnull
-	Response submitWorkflowByURL(@Nonnull List<URI> referenceList,
-			@Nonnull @Context UriInfo ui) throws NoCreateException,
-			NoUpdateException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(RUNS)
-	@Description("Produces the description of the operations on the "
-			+ "collection of runs.")
-	Response runsOptions();
-
-	/**
-	 * @return A description of the policies supported by this server.
-	 */
-	@Path(POL)
-	@Description("The policies supported by this server.")
-	@Nonnull
-	PolicyView getPolicyDescription();
-
-	/**
-	 * Get a particular named run resource.
-	 * 
-	 * @param runName
-	 *            The name of the run.
-	 * @param uriInfo
-	 *            About the URI used to access this run.
-	 * @return A RESTful delegate for the run.
-	 * @throws UnknownRunException
-	 *             If the run handle is unknown to the current user.
-	 */
-	@Path(RUNS + "/{runName}")
-	@RolesAllowed(USER)
-	@Description("Get a particular named run resource to dispatch to.")
-	@Nonnull
-	TavernaServerRunREST getRunResource(
-			@Nonnull @PathParam("runName") String runName,
-			@Nonnull @Context UriInfo uriInfo) throws UnknownRunException;
-
-	/**
-	 * Factored out path names used in the {@link TavernaServerREST} interface
-	 * and related places.
-	 * 
-	 * @author Donal Fellows
-	 */
-	interface PathNames {
-		public static final String ROOT = "/";
-		public static final String RUNS = "runs";
-		public static final String POL = "policy";
-		public static final String POL_CAPABILITIES = "capabilities";
-		public static final String POL_RUN_LIMIT = "runLimit";
-		public static final String POL_OP_LIMIT = "operatingLimit";
-		public static final String POL_PERM_WF = "permittedWorkflows";
-		public static final String POL_PERM_LIST = "permittedListenerTypes";
-		public static final String POL_NOTIFIERS = "enabledNotificationFabrics";
-	}
-
-	/**
-	 * Helper class for describing the server's user-facing management API via
-	 * JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "")
-	public static class ServerDescription extends VersionedElement {
-		/**
-		 * References to the collection of runs (known about by the current
-		 * user) in this server.
-		 */
-		public Uri runs;
-		/**
-		 * Reference to the policy description part of this server.
-		 */
-		public Uri policy;
-		/**
-		 * Reference to the Atom event feed produced by this server.
-		 */
-		public Uri feed;
-		/**
-		 * Reference to the interaction feed for this server.
-		 */
-		public Uri interactionFeed;
-
-		/** Make a blank server description. */
-		public ServerDescription() {
-		}
-
-		/**
-		 * Make a description of the server.
-		 * 
-		 * @param ui
-		 *            The factory for URIs.
-		 */
-		public ServerDescription(UriInfo ui, String interactionFeed) {
-			super(true);
-			String base = ui.getBaseUri().toString();
-			runs = new Uri(ui, RUNS);
-			policy = new Uri(ui, false, POL);
-			feed = new Uri(java.net.URI.create(base.replaceFirst("/rest$",
-					"/feed")));
-			if (interactionFeed != null && !interactionFeed.isEmpty())
-				this.interactionFeed = new Uri(
-						java.net.URI.create(interactionFeed));
-		}
-	}
-
-	/**
-	 * How to discover the publicly-visible policies supported by this server.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public interface PolicyView {
-		/**
-		 * Describe the URIs in this view of the server's policies.
-		 * 
-		 * @param ui
-		 *            About the URI used to retrieve the description.
-		 * @return The description, which may be serialised as XML or JSON.
-		 */
-		@GET
-		@Path(ROOT)
-		@Produces({ XML, JSON })
-		@Description("Describe the parts of this policy.")
-		@Nonnull
-		public PolicyDescription getDescription(@Nonnull @Context UriInfo ui);
-
-		/**
-		 * Gets the maximum number of simultaneous runs that the user may
-		 * create. The <i>actual</i> number they can create may be lower than
-		 * this. If this number is lower than the number they currently have,
-		 * they will be unable to create any runs at all.
-		 * 
-		 * @return The maximum number of existing runs.
-		 */
-		@GET
-		@Path(POL_RUN_LIMIT)
-		@Produces("text/plain")
-		@RolesAllowed(USER)
-		@Description("Gets the maximum number of simultaneous runs in any "
-				+ "state that the user may create.")
-		@Nonnull
-		public int getMaxSimultaneousRuns();
-
-		/**
-		 * Gets the maximum number of simultaneous
-		 * {@linkplain org.taverna.server.master.common.Status.Operating
-		 * operating} runs that the user may create. The <i>actual</i> number
-		 * they can start may be lower than this. If this number is lower than
-		 * the number they currently have, they will be unable to start any runs
-		 * at all.
-		 * 
-		 * @return The maximum number of operating runs.
-		 */
-		@GET
-		@Path(POL_OP_LIMIT)
-		@Produces("text/plain")
-		@RolesAllowed(USER)
-		@Description("Gets the maximum number of simultaneously operating "
-				+ "runs that the user may have. Note that this is often a "
-				+ "global limit; it does not represent a promise that a "
-				+ "particular user may be able to have that many operating "
-				+ "runs at once.")
-		public int getMaxOperatingRuns();
-
-		/**
-		 * Gets the list of permitted workflows. Any workflow may be submitted
-		 * if the list is empty, otherwise it must be one of the workflows on
-		 * this list.
-		 * 
-		 * @return The list of workflow documents.
-		 */
-		@GET
-		@Path(POL_PERM_WF)
-		@Produces({ XML, JSON })
-		@RolesAllowed(USER)
-		@Description("Gets the list of permitted workflows.")
-		@Nonnull
-		public PermittedWorkflows getPermittedWorkflows();
-
-		/**
-		 * Gets the list of permitted event listener types. All event listeners
-		 * must be of a type described on this list.
-		 * 
-		 * @return The types of event listeners allowed.
-		 */
-		@GET
-		@Path(POL_PERM_LIST)
-		@Produces({ XML, JSON })
-		@RolesAllowed(USER)
-		@Description("Gets the list of permitted event listener types.")
-		@Nonnull
-		public PermittedListeners getPermittedListeners();
-
-		/**
-		 * Gets the list of supported, enabled notification fabrics. Each
-		 * corresponds (approximately) to a protocol, e.g., email.
-		 * 
-		 * @return List of notifier names; each is the scheme of a notification
-		 *         destination URI.
-		 */
-		@GET
-		@Path(POL_NOTIFIERS)
-		@Produces({ XML, JSON })
-		@RolesAllowed(USER)
-		@Description("Gets the list of supported, enabled notification "
-				+ "fabrics. Each corresponds (approximately) to a protocol, "
-				+ "e.g., email.")
-		@Nonnull
-		public EnabledNotificationFabrics getEnabledNotifiers();
-
-		@GET
-		@Path(POL_CAPABILITIES)
-		@Produces({ XML, JSON })
-		@RolesAllowed(USER)
-		@Description("Gets a description of the capabilities supported by "
-				+ "this installation of Taverna Server.")
-		@Nonnull
-		public CapabilityList getCapabilities();
-
-		/**
-		 * A description of the parts of a server policy.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlRootElement
-		@XmlType(name = "")
-		public static class PolicyDescription extends VersionedElement {
-			/**
-			 * Where to go to find out about the maximum number of runs.
-			 */
-			public Uri runLimit;
-			/**
-			 * Where to go to find out about the maximum number of operating
-			 * runs.
-			 */
-			public Uri operatingLimit;
-			/**
-			 * Where to go to find out about what workflows are allowed.
-			 */
-			public Uri permittedWorkflows;
-			/**
-			 * Where to go to find out about what listeners are allowed.
-			 */
-			public Uri permittedListenerTypes;
-			/**
-			 * How notifications may be sent.
-			 */
-			public Uri enabledNotificationFabrics;
-
-			public Uri capabilities;
-
-			/** Make a blank server description. */
-			public PolicyDescription() {
-			}
-
-			/**
-			 * Make a server description.
-			 * 
-			 * @param ui
-			 *            About the URI used to access this description.
-			 */
-			public PolicyDescription(UriInfo ui) {
-				super(true);
-				runLimit = new Uri(ui, false, POL_RUN_LIMIT);
-				operatingLimit = new Uri(ui, false, POL_OP_LIMIT);
-				permittedWorkflows = new Uri(ui, false, POL_PERM_WF);
-				permittedListenerTypes = new Uri(ui, false, POL_PERM_LIST);
-				enabledNotificationFabrics = new Uri(ui, false, POL_NOTIFIERS);
-				capabilities = new Uri(ui, false, POL_CAPABILITIES);
-			}
-		}
-
-		/**
-		 * A list of Taverna Server capabilities.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlRootElement(name = "capabilities")
-		@XmlType(name = "")
-		public static class CapabilityList {
-			@XmlElement(name = "capability", namespace = SERVER)
-			public List<Capability> capability = new ArrayList<>();
-		}
-	}
-
-	/**
-	 * Helper class for describing the workflows that are allowed via JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "")
-	public static class PermittedWorkflows {
-		/** The workflows that are permitted. */
-		@XmlElement
-		public List<URI> workflow;
-
-		/**
-		 * Make an empty list of permitted workflows.
-		 */
-		public PermittedWorkflows() {
-			workflow = new ArrayList<>();
-		}
-
-		/**
-		 * Make a list of permitted workflows.
-		 * 
-		 * @param permitted
-		 */
-		public PermittedWorkflows(List<URI> permitted) {
-			if (permitted == null)
-				workflow = new ArrayList<>();
-			else
-				workflow = new ArrayList<>(permitted);
-		}
-	}
-
-	/**
-	 * Helper class for describing the listener types that are allowed via JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "")
-	public static class PermittedListeners {
-		/** The listener types that are permitted. */
-		@XmlElement
-		public List<String> type;
-
-		/**
-		 * Make an empty list of permitted listener types.
-		 */
-		public PermittedListeners() {
-			type = new ArrayList<>();
-		}
-
-		/**
-		 * Make a list of permitted listener types.
-		 * 
-		 * @param listenerTypes
-		 */
-		public PermittedListeners(List<String> listenerTypes) {
-			type = listenerTypes;
-		}
-	}
-
-	/**
-	 * Helper class for describing the workflow runs.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "")
-	public static class RunList {
-		/** The references to the workflow runs. */
-		@XmlElement
-		public List<RunReference> run;
-
-		/**
-		 * Make an empty list of run references.
-		 */
-		public RunList() {
-			run = new ArrayList<>();
-		}
-
-		/**
-		 * Make a list of references to workflow runs.
-		 * 
-		 * @param runs
-		 *            The mapping of runs to describe.
-		 * @param ub
-		 *            How to construct URIs to the runs. Must have already been
-		 *            secured as it needs to have its pattern applied.
-		 */
-		public RunList(Map<String, TavernaRun> runs, UriBuilder ub) {
-			run = new ArrayList<>(runs.size());
-			for (String name : runs.keySet())
-				run.add(new RunReference(name, ub));
-		}
-	}
-
-	/**
-	 * Helper class for describing the listener types that are allowed via JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "")
-	public static class EnabledNotificationFabrics {
-		/** The notification fabrics that are enabled. */
-		@XmlElement
-		public List<String> notifier;
-
-		/**
-		 * Make an empty list of enabled notifiers.
-		 */
-		public EnabledNotificationFabrics() {
-			notifier = new ArrayList<>();
-		}
-
-		/**
-		 * Make a list of enabled notifiers.
-		 * 
-		 * @param enabledNodifiers
-		 */
-		public EnabledNotificationFabrics(List<String> enabledNodifiers) {
-			notifier = enabledNodifiers;
-		}
-	}
-
-	/**
-	 * The interface exposed by the Atom feed of events.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@RolesAllowed(USER)
-	public interface EventFeed {
-		/**
-		 * @return the feed of events for the current user.
-		 */
-		@GET
-		@Path("/")
-		@Produces("application/atom+xml;type=feed")
-		@Description("Get an Atom feed for the user's events.")
-		@Nonnull
-		Feed getFeed(@Context UriInfo ui);
-
-		/**
-		 * @param id
-		 *            The identifier for a particular event.
-		 * @return the details about the given event.
-		 */
-		@GET
-		@Path("{id}")
-		@Produces("application/atom+xml;type=entry")
-		@Description("Get a particular Atom event.")
-		@Nonnull
-		Entry getEvent(@Nonnull @PathParam("id") String id);
-	}
-
-	/**
-	 * A reference to a workflow hosted on some public HTTP server.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "workflowurl")
-	@XmlType(name = "WorkflowReference")
-	public static class WorkflowReference {
-		@XmlValue
-		@XmlSchemaType(name = "anyURI")
-		public URI url;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java
deleted file mode 100644
index ef6ddd4..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.joda.time.format.ISODateTimeFormat.basicDateTime;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
-import static org.taverna.server.master.interaction.InteractionFeedSupport.FEED_URL_DIR;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.ROBUNDLE;
-import static org.taverna.server.master.rest.ContentTypes.TEXT;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.GENERATE_PROVENANCE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.IN;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LISTEN;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LOG;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.NAME;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.OUT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.PROFILE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.ROOT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.RUNBUNDLE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.SEC;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STATUS;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDERR;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDOUT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_CREATE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_EXPIRE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_FINISH;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_START;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.USAGE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.WF;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.JAXBException;
-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;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.joda.time.format.DateTimeFormatter;
-import org.taverna.server.master.common.Namespaces;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.NotOwnerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.port_description.OutputDescription;
-
-/**
- * This represents how a Taverna Server workflow run looks to a RESTful API.
- * 
- * @author Donal Fellows.
- */
-@Description("This represents how a Taverna Server workflow run looks to a "
-		+ "RESTful API.")
-@RolesAllowed(USER)
-public interface TavernaServerRunREST {
-	/**
-	 * Describes a workflow run.
-	 * 
-	 * @param ui
-	 *            About the URI used to access this resource.
-	 * @return The description.
-	 */
-	@GET
-	@Path(ROOT)
-	@Description("Describes a workflow run.")
-	@Produces({ XML, JSON })
-	@Nonnull
-	public RunDescription getDescription(@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Deletes a workflow run.
-	 * 
-	 * @return An HTTP response to the deletion.
-	 * @throws NoUpdateException
-	 *             If the user may see the handle but may not delete it.
-	 */
-	@DELETE
-	@Path(ROOT)
-	@Description("Deletes a workflow run.")
-	@Nonnull
-	public Response destroy() throws NoUpdateException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ROOT)
-	@Description("Produces the description of the run.")
-	Response runOptions();
-
-	/**
-	 * Returns the workflow document used to create the workflow run.
-	 * 
-	 * @return The workflow document.
-	 */
-	@GET
-	@Path(WF)
-	@Produces({ T2FLOW, SCUFL2, XML, JSON })
-	@Description("Gives the workflow document used to create the workflow run.")
-	@Nonnull
-	public Workflow getWorkflow();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(WF)
-	@Description("Produces the description of the run workflow.")
-	Response workflowOptions();
-
-	/** Get the workflow name. */
-	@GET
-	@Path(NAME)
-	@Produces(TEXT)
-	@Description("Gives the descriptive name of the workflow run.")
-	@Nonnull
-	public String getName();
-
-	/**
-	 * Set the workflow name.
-	 * 
-	 * @throws NoUpdateException
-	 *             If the user is not permitted to change the workflow.
-	 */
-	@PUT
-	@Path(NAME)
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Description("Set the descriptive name of the workflow run. Note that "
-			+ "this value may be arbitrarily truncated by the implementation.")
-	@Nonnull
-	public String setName(String name) throws NoUpdateException;
-
-	/** Produce the workflow name HTTP operations. */
-	@OPTIONS
-	@Path(NAME)
-	@Description("Produces the description of the operations on the run's "
-			+ "descriptive name.")
-	@Nonnull
-	Response nameOptions();
-
-	/**
-	 * Produces the name of the workflow's main profile.
-	 * 
-	 * @return The main profile name, or the empty string if there is no such
-	 *         profile.
-	 */
-	@GET
-	@Path(PROFILE)
-	@Produces(TEXT)
-	@Description("Gives the name of the workflow's main profile, or the empty string if none is defined.")
-	@Nonnull
-	String getMainProfileName();
-
-	/**
-	 * Get a description of the profiles supported by the workflow document used
-	 * to create this run.
-	 * 
-	 * @return A description of the supported profiles.
-	 */
-	@GET
-	@Path(PROFILE)
-	@Produces({ XML, JSON })
-	@Description("Describes what profiles exist on the workflow.")
-	@Nonnull
-	ProfileList getProfiles();
-
-	/** Produce the workflow profile HTTP operations. */
-	@OPTIONS
-	@Path(PROFILE)
-	@Description("Produces the description of the operations on the run's "
-			+ "profile.")
-	@Nonnull
-	Response profileOptions();
-
-	/**
-	 * Returns a resource that represents the workflow run's security
-	 * properties. These may only be accessed by the owner.
-	 * 
-	 * @return The security resource.
-	 * @throws NotOwnerException
-	 *             If the accessing principal isn't the owning principal.
-	 */
-	@Path(SEC)
-	@Description("Access the workflow run's security.")
-	@Nonnull
-	public TavernaServerSecurityREST getSecurity() throws NotOwnerException;
-
-	/**
-	 * Returns the time when the workflow run becomes eligible for automatic
-	 * deletion.
-	 * 
-	 * @return When the run expires.
-	 */
-	@GET
-	@Path(T_EXPIRE)
-	@Produces(TEXT)
-	@Description("Gives the time when the workflow run becomes eligible for "
-			+ "automatic deletion.")
-	@Nonnull
-	public String getExpiryTime();
-
-	/**
-	 * Sets the time when the workflow run becomes eligible for automatic
-	 * deletion.
-	 * 
-	 * @param expiry
-	 *            When the run will expire.
-	 * @return When the run will actually expire.
-	 * @throws NoUpdateException
-	 *             If the current user is not permitted to manage the lifetime
-	 *             of the run.
-	 */
-	@PUT
-	@Path(T_EXPIRE)
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Description("Sets the time when the workflow run becomes eligible for "
-			+ "automatic deletion.")
-	@Nonnull
-	public String setExpiryTime(@Nonnull String expiry)
-			throws NoUpdateException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(T_EXPIRE)
-	@Description("Produces the description of the run expiry.")
-	Response expiryOptions();
-
-	/**
-	 * Returns the time when the workflow run was created.
-	 * 
-	 * @return When the run was first submitted to the server.
-	 */
-	@GET
-	@Path(T_CREATE)
-	@Produces(TEXT)
-	@Description("Gives the time when the workflow run was first submitted "
-			+ "to the server.")
-	@Nonnull
-	public String getCreateTime();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(T_CREATE)
-	@Description("Produces the description of the run create time.")
-	Response createTimeOptions();
-
-	/**
-	 * Returns the time when the workflow run was started (through a user-driven
-	 * state change).
-	 * 
-	 * @return When the run was started, or <tt>null</tt>.
-	 */
-	@GET
-	@Path(T_START)
-	@Produces(TEXT)
-	@Description("Gives the time when the workflow run was started, or an "
-			+ "empty string if the run has not yet started.")
-	@Nonnull
-	public String getStartTime();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(T_START)
-	@Description("Produces the description of the run start time.")
-	Response startTimeOptions();
-
-	/**
-	 * Returns the time when the workflow run was detected to have finished.
-	 * 
-	 * @return When the run finished, or <tt>null</tt>.
-	 */
-	@GET
-	@Path(T_FINISH)
-	@Produces(TEXT)
-	@Description("Gives the time when the workflow run was first detected as "
-			+ "finished, or an empty string if it has not yet finished "
-			+ "(including if it has never started).")
-	@Nonnull
-	public String getFinishTime();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(T_FINISH)
-	@Description("Produces the description of the run finish time.")
-	Response finishTimeOptions();
-
-	/**
-	 * Gets the current status of the workflow run.
-	 * 
-	 * @return The status code.
-	 */
-	@GET
-	@Path(STATUS)
-	@Produces(TEXT)
-	@Description("Gives the current status of the workflow run.")
-	@Nonnull
-	public String getStatus();
-
-	/**
-	 * Sets the status of the workflow run. This does nothing if the status code
-	 * is the same as the run's current state.
-	 * 
-	 * @param status
-	 *            The new status code.
-	 * @return Description of what status the run is actually in, or a 202 to
-	 *         indicate that things are still changing.
-	 * @throws NoUpdateException
-	 *             If the current user is not permitted to update the run.
-	 * @throws BadStateChangeException
-	 *             If the state cannot be modified in the manner requested.
-	 */
-	@PUT
-	@Path(STATUS)
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Description("Attempts to update the status of the workflow run.")
-	@Nonnull
-	public Response setStatus(@Nonnull String status) throws NoUpdateException,
-			BadStateChangeException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(STATUS)
-	@Description("Produces the description of the run status.")
-	Response statusOptions();
-
-	/**
-	 * Get the working directory of this workflow run.
-	 * 
-	 * @return A RESTful delegate for the working directory.
-	 */
-	@Path(DIR)
-	@Description("Get the working directory of this workflow run.")
-	@Nonnull
-	public TavernaServerDirectoryREST getWorkingDirectory();
-
-	/**
-	 * Get the event listeners attached to this workflow run.
-	 * 
-	 * @return A RESTful delegate for the list of listeners.
-	 */
-	@Path(LISTEN)
-	@Description("Get the event listeners attached to this workflow run.")
-	@Nonnull
-	public TavernaServerListenersREST getListeners();
-
-	/**
-	 * Get a delegate for working with the inputs to this workflow run.
-	 * 
-	 * @param ui
-	 *            About the URI used to access this resource.
-	 * @return A RESTful delegate for the inputs.
-	 */
-	@Path(IN)
-	@Description("Get the inputs to this workflow run.")
-	@Nonnull
-	public TavernaServerInputREST getInputs(@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Get the output Baclava file for this workflow run.
-	 * 
-	 * @return The filename, or empty string to indicate that the outputs will
-	 *         be written to the <tt>out</tt> directory.
-	 */
-	@GET
-	@Path(OUT)
-	@Produces(TEXT)
-	@Description("Gives the Baclava file where output will be written; empty "
-			+ "means use multiple simple files in the out directory.")
-	@Nonnull
-	public String getOutputFile();
-
-	/**
-	 * Get a description of the outputs.
-	 * 
-	 * @param ui
-	 *            About the URI used to access this operation.
-	 * @return A description of the outputs (higher level than the filesystem).
-	 * @throws BadStateChangeException
-	 *             If the run is in the {@link Status#Initialized Initialized}
-	 *             state.
-	 * @throws FilesystemAccessException
-	 *             If problems occur when accessing the filesystem.
-	 * @throws NoDirectoryEntryException
-	 *             If things are odd in the filesystem.
-	 */
-	@GET
-	@Path(OUT)
-	@Produces({ XML, JSON })
-	@Description("Gives a description of the outputs, as currently understood")
-	@Nonnull
-	public OutputDescription getOutputDescription(@Nonnull @Context UriInfo ui)
-			throws BadStateChangeException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Set the output Baclava file for this workflow run.
-	 * 
-	 * @param filename
-	 *            The Baclava file to use, or empty to make the outputs be
-	 *            written to individual files in the <tt>out</tt> subdirectory
-	 *            of the working directory.
-	 * @return The Baclava file as actually set.
-	 * @throws NoUpdateException
-	 *             If the current user is not permitted to update the run.
-	 * @throws FilesystemAccessException
-	 *             If the filename is invalid (starts with <tt>/</tt> or
-	 *             contains a <tt>..</tt> segment).
-	 * @throws BadStateChangeException
-	 *             If the workflow is not in the Initialized state.
-	 */
-	@PUT
-	@Path(OUT)
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Description("Sets the Baclava file where output will be written; empty "
-			+ "means use multiple simple files in the out directory.")
-	@Nonnull
-	public String setOutputFile(@Nonnull String filename)
-			throws NoUpdateException, FilesystemAccessException,
-			BadStateChangeException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(OUT)
-	@Description("Produces the description of the run output.")
-	Response outputOptions();
-
-	/**
-	 * Get a handle to the interaction feed.
-	 * 
-	 * @return
-	 */
-	@Path(FEED_URL_DIR)
-	@Description("Access the interaction feed for the workflow run.")
-	@Nonnull
-	InteractionFeedREST getInteractionFeed();
-
-	/**
-	 * @return The stdout for the workflow run, or empty string if the run has
-	 *         not yet started.
-	 * @throws NoListenerException
-	 */
-	@GET
-	@Path(STDOUT)
-	@Description("Return the stdout for the workflow run.")
-	@Produces(TEXT)
-	@Nonnull
-	String getStdout() throws NoListenerException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(STDOUT)
-	@Description("Return the stdout for the workflow run.")
-	Response stdoutOptions();
-
-	/**
-	 * @return The stderr for the workflow run, or empty string if the run has
-	 *         not yet started.
-	 * @throws NoListenerException
-	 */
-	@GET
-	@Path(STDERR)
-	@Description("Return the stderr for the workflow run.")
-	@Produces(TEXT)
-	@Nonnull
-	String getStderr() throws NoListenerException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(STDERR)
-	@Description("Return the stderr for the workflow run.")
-	Response stderrOptions();
-
-	/**
-	 * @return The usage record for the workflow run, wrapped in a Response, or
-	 *         "empty content" if the run has not yet finished.
-	 * @throws NoListenerException
-	 * @throws JAXBException
-	 */
-	@GET
-	@Path(USAGE)
-	@Description("Return the usage record for the workflow run.")
-	@Produces(XML)
-	@Nonnull
-	Response getUsage() throws NoListenerException, JAXBException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(USAGE)
-	@Description("Return the usage record for the workflow run.")
-	Response usageOptions();
-
-	/**
-	 * @return The log for the workflow run, or empty string if the run has not
-	 *         yet started.
-	 */
-	@GET
-	@Path(LOG)
-	@Description("Return the log for the workflow run.")
-	@Produces(TEXT)
-	@Nonnull
-	Response getLogContents();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(LOG)
-	@Description("Return the log for the workflow run.")
-	Response logOptions();
-
-	/**
-	 * @return The log for the workflow run, or empty string if the run has not
-	 *         yet started.
-	 */
-	@GET
-	@Path(RUNBUNDLE)
-	@Description("Return the run bundle for the workflow run.")
-	@Produces(ROBUNDLE)
-	@Nonnull
-	Response getRunBundle();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(RUNBUNDLE)
-	@Description("Return the run bundle for the workflow run.")
-	Response runBundleOptions();
-
-	/**
-	 * @return Whether to create the run bundle for the workflow run. Only
-	 *         usefully set-able before the start of the run.
-	 */
-	@GET
-	@Path(GENERATE_PROVENANCE)
-	@Description("Whether to create the run bundle for the workflow run.")
-	@Produces(TEXT)
-	@Nonnull
-	boolean getGenerateProvenance();
-
-	/**
-	 * @param provenanceFlag
-	 *            Whether to create the run bundle for the workflow run. Only
-	 *            usefully set-able before the start of the run.
-	 * @return What it was actually set to.
-	 * @throws NoUpdateException 
-	 */
-	@PUT
-	@Path(GENERATE_PROVENANCE)
-	@Description("Whether to create the run bundle for the workflow run.")
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Nonnull
-	boolean setGenerateProvenance(boolean provenanceFlag) throws NoUpdateException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(GENERATE_PROVENANCE)
-	@Description("Whether to create the run bundle for the workflow run.")
-	Response generateProvenanceOptions();
-
-	/**
-	 * Factored out path names used in the {@link TavernaServerRunREST}
-	 * interface and related places.
-	 * 
-	 * @author Donal Fellows
-	 */
-	interface PathNames {
-		public static final String ROOT = "/";
-		public static final String WF = "workflow";
-		public static final String DIR = "wd";
-		public static final String NAME = "name";
-		public static final String T_EXPIRE = "expiry";
-		public static final String T_CREATE = "createTime";
-		public static final String T_START = "startTime";
-		public static final String T_FINISH = "finishTime";
-		public static final String STATUS = "status";
-		public static final String IN = "input";
-		public static final String OUT = "output";
-		public static final String PROFILE = "profile";
-		public static final String LISTEN = "listeners";
-		public static final String SEC = "security";
-		public static final String STDOUT = "stdout";
-		public static final String STDERR = "stderr";
-		public static final String USAGE = "usage";
-		public static final String LOG = "log";
-		public static final String RUNBUNDLE = "run-bundle";
-		public static final String GENERATE_PROVENANCE = "generate-provenance";
-	}
-
-	/**
-	 * The description of where everything is in a RESTful view of a workflow
-	 * run. Done with JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "")
-	public static class RunDescription extends VersionedElement {
-		/** The identity of the owner of the workflow run. */
-		@XmlAttribute(namespace = Namespaces.SERVER_REST)
-		public String owner;
-		/** The description of the expiry. */
-		public Expiry expiry;
-		/** The location of the creation workflow description. */
-		public Uri creationWorkflow;
-		/** The location of the creation time property. */
-		public Uri createTime;
-		/** The location of the start time property. */
-		public Uri startTime;
-		/** The location of the finish time property. */
-		public Uri finishTime;
-		/** The location of the status description. */
-		public Uri status;
-		/** The location of the working directory. */
-		public Uri workingDirectory;
-		/** The location of the inputs. */
-		public Uri inputs;
-		/** The location of the Baclava output. */
-		public Uri output;
-		/** The location of the security context. */
-		public Uri securityContext;
-		/** The list of listeners. */
-		public ListenerList listeners;
-		/** The location of the interaction feed. */
-		public Uri interaction;
-		/** The name of the run. */
-		public Uri name;
-		/** The stdout of the run. */
-		public Uri stdout;
-		/** The stderr of the run. */
-		public Uri stderr;
-		/** The usage record for the run. */
-		public Uri usage;
-		/** The log from the run. */
-		public Uri log;
-		/** The bundle describing the run. */
-		@XmlElement(name = RUNBUNDLE)
-		public Uri runBundle;
-		/** Whether to generate a bundle describing the run. */
-		@XmlElement(name = GENERATE_PROVENANCE)
-		public Uri generateProvenance;
-
-		/**
-		 * How to describe a run's expiry.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "")
-		public static class Expiry {
-			/**
-			 * Where to go to read the exiry
-			 */
-			@XmlAttribute(name = "href", namespace = Namespaces.XLINK)
-			@XmlSchemaType(name = "anyURI")
-			public URI ref;
-			/**
-			 * What the expiry currently is.
-			 */
-			@XmlValue
-			public String timeOfDeath;
-
-			/**
-			 * Make a blank expiry description.
-			 */
-			public Expiry() {
-			}
-
-			private static DateTimeFormatter dtf;
-
-			Expiry(TavernaRun r, UriInfo ui, String path, String... parts) {
-				ref = fromUri(new Uri(ui, true, path, parts).ref).build();
-				if (dtf == null)
-					dtf = basicDateTime();
-				timeOfDeath = dtf.print(r.getExpiry().getTime());
-			}
-		}
-
-		/**
-		 * The description of a list of listeners attached to a run.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "")
-		public static class ListenerList extends Uri {
-			/**
-			 * The references to the individual listeners.
-			 */
-			public List<Uri> listener;
-
-			/**
-			 * An empty description of listeners.
-			 */
-			public ListenerList() {
-				listener = new ArrayList<>();
-			}
-
-			/**
-			 * @param r
-			 *            The run whose listeners we're talking about.
-			 * @param ub
-			 *            Uri factory; must've been secured
-			 */
-			private ListenerList(TavernaRun r, UriBuilder ub) {
-				super(ub);
-				listener = new ArrayList<>(r.getListeners().size());
-				UriBuilder pathUB = ub.clone().path("{name}");
-				for (Listener l : r.getListeners())
-					listener.add(new Uri(pathUB.build(l.getName())));
-			}
-
-			/**
-			 * @param run
-			 *            The run whose listeners we're talking about.
-			 * @param ui
-			 *            The source of information about URIs.
-			 * @param path
-			 *            Where we are relative to the URI source.
-			 * @param parts
-			 *            Anything required to fill out the path.
-			 */
-			ListenerList(TavernaRun run, UriInfo ui, String path,
-					String... parts) {
-				this(run, secure(fromUri(new Uri(ui, path, parts).ref)));
-			}
-		}
-
-		/**
-		 * An empty description of a run.
-		 */
-		public RunDescription() {
-		}
-
-		/**
-		 * A description of a particular run.
-		 * 
-		 * @param run
-		 *            The run to describe.
-		 * @param ui
-		 *            The factory for URIs.
-		 */
-		public RunDescription(TavernaRun run, UriInfo ui) {
-			super(true);
-			creationWorkflow = new Uri(ui, WF);
-			expiry = new Expiry(run, ui, T_EXPIRE);
-			status = new Uri(ui, STATUS);
-			workingDirectory = new Uri(ui, DIR);
-			listeners = new ListenerList(run, ui, LISTEN);
-			securityContext = new Uri(ui, SEC);
-			inputs = new Uri(ui, IN);
-			output = new Uri(ui, OUT);
-			createTime = new Uri(ui, T_CREATE);
-			startTime = new Uri(ui, T_START);
-			finishTime = new Uri(ui, T_FINISH);
-			interaction = new Uri(ui, FEED_URL_DIR);
-			name = new Uri(ui, NAME);
-			owner = run.getSecurityContext().getOwner().getName();
-			stdout = new Uri(ui, STDOUT);
-			stderr = new Uri(ui, STDERR);
-			usage = new Uri(ui, USAGE);
-			log = new Uri(ui, LOG);
-			runBundle = new Uri(ui, RUNBUNDLE);
-			generateProvenance = new Uri(ui, GENERATE_PROVENANCE);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java
deleted file mode 100644
index f5101e7..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest;
-/*
- * 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.
- */
-
-import static java.util.Collections.emptyList;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.TEXT;
-import static org.taverna.server.master.rest.ContentTypes.XML;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.CREDS;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_CRED;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_PERM;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_TRUST;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.OWNER;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.PERMS;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ROOT;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.TRUSTS;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElements;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCredentialException;
-
-/**
- * Manages the security of the workflow run. In general, only the owner of a run
- * may access this resource. Many of these security-related resources may only
- * be changed before the run is set to operating.
- * 
- * @author Donal Fellows
- */
-@RolesAllowed(USER)
-@Description("Manages the security of the workflow run. In general, only the "
-		+ "owner of a run may access this resource.")
-public interface TavernaServerSecurityREST {
-	interface PathNames {
-		final String ROOT = "/";
-		final String OWNER = "owner";
-		final String CREDS = "credentials";
-		final String ONE_CRED = CREDS + "/{id}";
-		final String TRUSTS = "trusts";
-		final String ONE_TRUST = TRUSTS + "/{id}";
-		final String PERMS = "permissions";
-		final String ONE_PERM = PERMS + "/{id}";
-	}
-
-	/**
-	 * Gets a description of the security information supported by the workflow
-	 * run.
-	 * 
-	 * @param ui
-	 *            About the URI used to access this resource.
-	 * @return A description of the security information.
-	 */
-	@GET
-	@Path(ROOT)
-	@Produces({ XML, JSON })
-	@Description("Gives a description of the security information supported "
-			+ "by the workflow run.")
-	@Nonnull
-	Descriptor describe(@Nonnull @Context UriInfo ui);
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ROOT)
-	@Description("Produces the description of the run security.")
-	Response descriptionOptions();
-
-	/**
-	 * Gets the identity of who owns the workflow run.
-	 * 
-	 * @return The name of the owner of the run.
-	 */
-	@GET
-	@Path(OWNER)
-	@Produces(TEXT)
-	@Description("Gives the identity of who owns the workflow run.")
-	@Nonnull
-	String getOwner();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(OWNER)
-	@Description("Produces the description of the run owner.")
-	Response ownerOptions();
-
-	/*
-	 * @PUT @Path("/") @Consumes(ContentTypes.BYTES) @CallCounted @Nonnull
-	 * public void set(@Nonnull InputStream contents, @Nonnull @Context UriInfo
-	 * ui);
-	 */
-
-	/**
-	 * @return A list of credentials supplied to this workflow run.
-	 */
-	@GET
-	@Path(CREDS)
-	@Produces({ XML, JSON })
-	@Description("Gives a list of credentials supplied to this workflow run.")
-	@Nonnull
-	CredentialList listCredentials();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(CREDS)
-	@Description("Produces the description of the run credentials' operations.")
-	Response credentialsOptions();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ONE_CRED)
-	@Description("Produces the description of one run credential's operations.")
-	Response credentialOptions(@PathParam("id") String id);
-
-	/**
-	 * Describe a particular credential.
-	 * 
-	 * @param id
-	 *            The id of the credential to fetch.
-	 * @return The description of the credential.
-	 * @throws NoCredentialException
-	 *             If the credential doesn't exist.
-	 */
-	@GET
-	@Path(ONE_CRED)
-	@Produces({ XML, JSON })
-	@Description("Describes a particular credential.")
-	@Nonnull
-	CredentialHolder getParticularCredential(@Nonnull @PathParam("id") String id)
-			throws NoCredentialException;
-
-	/**
-	 * Update a particular credential.
-	 * 
-	 * @param id
-	 *            The id of the credential to update.
-	 * @param c
-	 *            The details of the credential to use in the update.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return Description of the updated credential.
-	 * @throws InvalidCredentialException
-	 *             If the credential description isn't valid.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@PUT
-	@Path(ONE_CRED)
-	@Consumes({ XML, JSON })
-	@Produces({ XML, JSON })
-	@Description("Updates a particular credential.")
-	@Nonnull
-	CredentialHolder setParticularCredential(
-			@Nonnull @PathParam("id") String id, @Nonnull CredentialHolder c,
-			@Nonnull @Context UriInfo ui) throws InvalidCredentialException,
-			BadStateChangeException;
-
-	/**
-	 * Adds a new credential.
-	 * 
-	 * @param c
-	 *            The details of the credential to create.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return Description of the created credential.
-	 * @throws InvalidCredentialException
-	 *             If the credential description isn't valid.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@POST
-	@Path(CREDS)
-	@Consumes({ XML, JSON })
-	@Description("Creates a new credential.")
-	@Nonnull
-	Response addCredential(@Nonnull CredentialHolder c,
-			@Nonnull @Context UriInfo ui) throws InvalidCredentialException,
-			BadStateChangeException;
-
-	/**
-	 * Deletes all credentials associated with a run.
-	 * 
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return A characterisation of a successful delete.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@DELETE
-	@Path(CREDS)
-	@Description("Deletes all credentials.")
-	@Nonnull
-	Response deleteAllCredentials(@Nonnull @Context UriInfo ui)
-			throws BadStateChangeException;
-
-	/**
-	 * Deletes one credential associated with a run.
-	 * 
-	 * @param id
-	 *            The identity of the credential to delete.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return A characterisation of a successful delete.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@DELETE
-	@Path(ONE_CRED)
-	@Description("Deletes a particular credential.")
-	@Nonnull
-	Response deleteCredential(@Nonnull @PathParam("id") String id,
-			@Nonnull @Context UriInfo ui) throws BadStateChangeException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(TRUSTS)
-	@Description("Produces the description of the run trusted certificates' "
-			+ "operations.")
-	Response trustsOptions();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ONE_TRUST)
-	@Description("Produces the description of one run trusted certificate's "
-			+ "operations.")
-	Response trustOptions(@PathParam("id") String id);
-
-	/**
-	 * @return A list of trusted identities supplied to this workflow run.
-	 */
-	@GET
-	@Path(TRUSTS)
-	@Produces({ XML, JSON })
-	@Description("Gives a list of trusted identities supplied to this "
-			+ "workflow run.")
-	@Nonnull
-	TrustList listTrusted();
-
-	/**
-	 * Describe a particular trusted identity.
-	 * 
-	 * @param id
-	 *            The id of the trusted identity to fetch.
-	 * @return The description of the trusted identity.
-	 * @throws NoCredentialException
-	 *             If the trusted identity doesn't exist.
-	 */
-	@GET
-	@Path(ONE_TRUST)
-	@Produces({ XML, JSON })
-	@Description("Describes a particular trusted identity.")
-	@Nonnull
-	Trust getParticularTrust(@Nonnull @PathParam("id") String id)
-			throws NoCredentialException;
-
-	/**
-	 * Update a particular trusted identity.
-	 * 
-	 * @param id
-	 *            The id of the trusted identity to update.
-	 * @param t
-	 *            The details of the trusted identity to use in the update.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return Description of the updated trusted identity.
-	 * @throws InvalidCredentialException
-	 *             If the trusted identity description isn't valid.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@PUT
-	@Path(ONE_TRUST)
-	@Consumes({ XML, JSON })
-	@Produces({ XML, JSON })
-	@Description("Updates a particular trusted identity.")
-	@Nonnull
-	Trust setParticularTrust(@Nonnull @PathParam("id") String id,
-			@Nonnull Trust t, @Nonnull @Context UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException;
-
-	/**
-	 * Adds a new trusted identity.
-	 * 
-	 * @param t
-	 *            The details of the trusted identity to create.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return Description of the created trusted identity.
-	 * @throws InvalidCredentialException
-	 *             If the trusted identity description isn't valid.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@POST
-	@Path(TRUSTS)
-	@Consumes({ XML, JSON })
-	@Description("Adds a new trusted identity.")
-	@Nonnull
-	Response addTrust(@Nonnull Trust t, @Nonnull @Context UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException;
-
-	/**
-	 * Deletes all trusted identities associated with a run.
-	 * 
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return A characterisation of a successful delete.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@DELETE
-	@Path(TRUSTS)
-	@Description("Deletes all trusted identities.")
-	@Nonnull
-	Response deleteAllTrusts(@Nonnull @Context UriInfo ui)
-			throws BadStateChangeException;
-
-	/**
-	 * Deletes one trusted identity associated with a run.
-	 * 
-	 * @param id
-	 *            The identity of the trusted identity to delete.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return A characterisation of a successful delete.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@DELETE
-	@Path(ONE_TRUST)
-	@Description("Deletes a particular trusted identity.")
-	@Nonnull
-	Response deleteTrust(@Nonnull @PathParam("id") String id,
-			@Nonnull @Context UriInfo ui) throws BadStateChangeException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(PERMS)
-	@Description("Produces the description of the run permissions' operations.")
-	Response permissionsOptions();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ONE_PERM)
-	@Description("Produces the description of one run permission's operations.")
-	Response permissionOptions(@PathParam("id") String id);
-
-	/**
-	 * @return A list of (non-default) permissions associated with this workflow
-	 *         run.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 */
-	@GET
-	@Path(PERMS)
-	@Produces({ XML, JSON })
-	@Description("Gives a list of all non-default permissions associated with "
-			+ "the enclosing workflow run. By default, nobody has any access "
-			+ "at all except for the owner of the run.")
-	@Nonnull
-	PermissionsDescription describePermissions(@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Describe the particular permission granted to a user.
-	 * 
-	 * @param id
-	 *            The name of the user whose permissions are to be described.
-	 * @return The permission they are granted.
-	 */
-	@GET
-	@Path(ONE_PERM)
-	@Produces(TEXT)
-	@Description("Describes the permission granted to a particular user.")
-	@Nonnull
-	Permission describePermission(@Nonnull @PathParam("id") String id);
-
-	/**
-	 * Update the permission granted to a user.
-	 * 
-	 * @param id
-	 *            The name of the user whose permissions are to be updated. Note
-	 *            that the owner always has full permissions.
-	 * @param perm
-	 *            The permission level to set.
-	 * @return The permission level that has actually been set.
-	 */
-	@PUT
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Path(ONE_PERM)
-	@Description("Updates the permissions granted to a particular user.")
-	@Nonnull
-	Permission setPermission(@Nonnull @PathParam("id") String id,
-			@Nonnull Permission perm);
-
-	/**
-	 * Delete the permissions associated with a user, which restores them to the
-	 * default (no access unless they are the owner or have admin privileges).
-	 * 
-	 * @param id
-	 *            The name of the user whose permissions are to be revoked.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return An indication that the delete has been successful (or not).
-	 */
-	@DELETE
-	@Path(ONE_PERM)
-	@Description("Deletes (by resetting to default) the permissions "
-			+ "associated with a particular user.")
-	@Nonnull
-	Response deletePermission(@Nonnull @PathParam("id") String id,
-			@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Manufacture a permission setting for a previously-unknown user.
-	 * 
-	 * @param desc
-	 *            A description of the name of the user and the permission level
-	 *            to grant them.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return An indication that the create has been successful (or not).
-	 */
-	@POST
-	@Path(PERMS)
-	@Consumes({ XML, JSON })
-	@Description("Creates a new assignment of permissions to a particular user.")
-	@Nonnull
-	Response makePermission(@Nonnull PermissionDescription desc,
-			@Nonnull @Context UriInfo ui);
-
-	/**
-	 * A description of the security resources associated with a workflow run.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "securityDescriptor")
-	@XmlType(name = "SecurityDescriptor")
-	public static final class Descriptor extends VersionedElement {
-		/** The identity of the owner of the enclosing workflow run. */
-		@XmlElement
-		public String owner;
-		/** Where to get the permissions on the run. */
-		@XmlElement
-		public Uri permissions;
-
-		/** Characterisation of the credentials attached to the run. */
-		@XmlElement
-		public Credentials credentials;
-		/** Characterisation of the trusted certificates attached to the run. */
-		@XmlElement
-		public Trusts trusts;
-
-		public Descriptor() {
-		}
-
-		/**
-		 * Initialise a description of the security context.
-		 * 
-		 * @param ub
-		 *            How to build URIs.
-		 * @param owner
-		 *            Who owns the context.
-		 * @param credential
-		 *            The credentials associated with the context.
-		 * @param trust
-		 *            The trusted certificates associated with the context.
-		 */
-		public Descriptor(@Nonnull UriBuilder ub, @Nonnull String owner,
-				@Nonnull Credential[] credential, @Nonnull Trust[] trust) {
-			super(true);
-			this.owner = owner;
-			this.permissions = new Uri(ub, PERMS);
-			this.credentials = new Credentials(new Uri(ub, CREDS).ref,
-					credential);
-			this.trusts = new Trusts(new Uri(ub, TRUSTS).ref, trust);
-		}
-
-		/**
-		 * A description of credentials associated with a workflow run.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "CredentialCollection")
-		public static final class Credentials {
-			/** Reference to the collection of credentials */
-			@XmlAttribute(name = "href", namespace = XLINK)
-			@XmlSchemaType(name = "anyURI")
-			public URI href;
-			/** Descriptions of the credentials themselves. */
-			@XmlElement
-			public List<CredentialHolder> credential = new ArrayList<>();
-
-			public Credentials() {
-			}
-
-			/**
-			 * Initialise a description of the credentials.
-			 * 
-			 * @param uri
-			 *            the URI of the collection.
-			 * @param credential
-			 *            The credentials in the collection.
-			 */
-			public Credentials(@Nonnull URI uri,
-					@Nonnull Credential[] credential) {
-				this.href = uri;
-				for (Credential c : credential)
-					this.credential.add(new CredentialHolder(c));
-			}
-		}
-
-		/**
-		 * A description of trusted certificates associated with a workflow run.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "TrustCollection")
-		public static final class Trusts {
-			/** Reference to the collection of trusted certs */
-			@XmlAttribute(name = "href", namespace = XLINK)
-			@XmlSchemaType(name = "anyURI")
-			public URI href;
-			/** Descriptions of the trusted certs themselves. */
-			@XmlElement
-			public Trust[] trust;
-
-			public Trusts() {
-			}
-
-			/**
-			 * Initialise a description of the trusted certificates.
-			 * 
-			 * @param uri
-			 *            the URI of the collection.
-			 * @param trust
-			 *            The trusted certificates in the collection.
-			 */
-			public Trusts(@Nonnull URI uri, @Nonnull Trust[] trust) {
-				this.href = uri;
-				this.trust = trust.clone();
-			}
-		}
-	}
-
-	/**
-	 * A container for a credential, used to work around issues with type
-	 * inference in CXF's REST service handling and JAXB.
-	 * 
-	 * @see Credential.KeyPair
-	 * @see Credential.Password
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "credential")
-	@XmlType(name = "Credential")
-	public static final class CredentialHolder {
-		/**
-		 * The credential inside this holder.
-		 */
-		@XmlElements({
-				@XmlElement(name = "keypair", namespace = SERVER, type = Credential.KeyPair.class, required = true),
-				@XmlElement(name = "userpass", namespace = SERVER, type = Credential.Password.class, required = true) })
-		public Credential credential;
-
-		public CredentialHolder() {
-		}
-
-		public CredentialHolder(Credential credential) {
-			this.credential = credential;
-		}
-
-		/**
-		 * Convenience accessor function.
-		 * 
-		 * @return The keypair credential held in this holder.
-		 */
-		@XmlTransient
-		public Credential.KeyPair getKeypair() {
-			return (Credential.KeyPair) this.credential;
-		}
-
-		/**
-		 * Convenience accessor function.
-		 * 
-		 * @return The userpass credential held in this holder.
-		 */
-		@XmlTransient
-		public Credential.Password getUserpass() {
-			return (Credential.Password) this.credential;
-		}
-	}
-
-	/**
-	 * A simple list of credential descriptions.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "credentials")
-	public static final class CredentialList extends VersionedElement {
-		/** The descriptions of the credentials */
-		@XmlElement
-		@Nonnull
-		public List<CredentialHolder> credential = new ArrayList<>();
-
-		public CredentialList() {
-		}
-
-		/**
-		 * Initialise the list of credentials.
-		 * 
-		 * @param credential
-		 *            The descriptions of individual credentials.
-		 */
-		public CredentialList(@Nonnull Credential[] credential) {
-			super(true);
-			for (Credential c : credential)
-				this.credential.add(new CredentialHolder(c));
-		}
-	}
-
-	/**
-	 * A simple list of trusted certificate descriptions.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "trustedIdentities")
-	public static final class TrustList extends VersionedElement {
-		/** The descriptions of the trusted certificates */
-		@XmlElement
-		public Trust[] trust;
-
-		public TrustList() {
-		}
-
-		/**
-		 * Initialise the list of trusted certificates.
-		 * 
-		 * @param trust
-		 *            The descriptions of individual certificates.
-		 */
-		public TrustList(@Nonnull Trust[] trust) {
-			super(true);
-			this.trust = trust.clone();
-		}
-	}
-
-	/**
-	 * A description of the permissions granted to others by the owner of a
-	 * workflow run.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "permissionsDescriptor")
-	public static class PermissionsDescription extends VersionedElement {
-		/**
-		 * A description of the permissions granted to one user by the owner of
-		 * a workflow run.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlRootElement(name = "userPermission")
-		public static class LinkedPermissionDescription extends Uri {
-			/** Who is this granted to? */
-			@XmlElement
-			public String userName;
-			/** What are they granted? */
-			@XmlElement
-			public Permission permission;
-
-			public LinkedPermissionDescription() {
-			}
-
-			/**
-			 * Initialise a description of one user's permissions.
-			 * 
-			 * @param ub
-			 *            How to build the URI to this permission. Already
-			 *            secured.
-			 * @param userName
-			 *            Who this relates to.
-			 * @param permission
-			 *            What permission is granted.
-			 * @param strings
-			 *            Parameters to the URI builder.
-			 */
-			LinkedPermissionDescription(@Nonnull UriBuilder ub,
-					@Nonnull String userName, @Nonnull Permission permission,
-					String... strings) {
-				super(ub, strings);
-				this.userName = userName;
-				this.permission = permission;
-			}
-		}
-
-		/** List of descriptions of permissions. */
-		@XmlElement
-		public List<LinkedPermissionDescription> permission;
-
-		public PermissionsDescription() {
-			permission = emptyList();
-		}
-
-		/**
-		 * Initialise the description of a collection of permissions.
-		 * 
-		 * @param ub
-		 *            How to build URIs to this collection. Must have already
-		 *            been secured.
-		 * @param permissionMap
-		 *            The permissions to describe.
-		 */
-		public PermissionsDescription(@Nonnull UriBuilder ub,
-				@Nonnull Map<String, Permission> permissionMap) {
-			permission = new ArrayList<>();
-			List<String> userNames = new ArrayList<>(permissionMap.keySet());
-			Collections.sort(userNames);
-			for (String user : userNames)
-				permission.add(new LinkedPermissionDescription(ub, user,
-						permissionMap.get(user), user));
-		}
-	}
-
-	/**
-	 * An instruction to update the permissions for a user.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "permissionUpdate")
-	public static class PermissionDescription {
-		/** Who to set the permission for? */
-		@XmlElement
-		public String userName;
-		/** What permission to grant them? */
-		@XmlElement
-		public Permission permission;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java
deleted file mode 100644
index 3418975..0000000
--- a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- */
-package org.taverna.server.master.rest.handler;
-/*
- * 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.
- */
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.springframework.security.access.AccessDeniedException;
-
-public class AccessDeniedHandler extends HandlerCore implements
-		ExceptionMapper<AccessDeniedException> {
-	@Override
-	public Response toResponse(AccessDeniedException exception) {
-		return respond(FORBIDDEN, exception);
-	}
-}



[21/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/CompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/CompletionNotifier.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/CompletionNotifier.java
new file mode 100644
index 0000000..1868f94
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/CompletionNotifier.java
@@ -0,0 +1,58 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+
+/**
+ * How to convert a notification about the completion of a job into a message.
+ * 
+ * @author Donal Fellows
+ */
+public interface CompletionNotifier {
+	/**
+	 * @return The name of this notifier.
+	 */
+	String getName();
+
+	/**
+	 * Called to get the content of a message that a workflow run has finished.
+	 * 
+	 * @param name
+	 *            The name of the run.
+	 * @param run
+	 *            What run are we talking about.
+	 * @param code
+	 *            What the exit code was.
+	 * @return The plain-text content of the message.
+	 */
+	String makeCompletionMessage(String name, RemoteRunDelegate run, int code);
+
+	/**
+	 * Called to get the subject of the message to dispatch.
+	 * 
+	 * @param name
+	 *            The name of the run.
+	 * @param run
+	 *            What run are we talking about.
+	 * @param code
+	 *            What the exit code was.
+	 * @return The plain-text subject of the message.
+	 */
+	String makeMessageSubject(String name, RemoteRunDelegate run, int code);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/FactoryBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/FactoryBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/FactoryBean.java
new file mode 100644
index 0000000..d38f0cc
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/FactoryBean.java
@@ -0,0 +1,39 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.notification.atom.EventDAO;
+
+/**
+ * What the remote run really needs of its factory.
+ * 
+ * @author Donal Fellows
+ */
+public interface FactoryBean {
+	/**
+	 * @return Whether a run can actually be started at this time.
+	 */
+	boolean isAllowingRunsToStart();
+
+	/**
+	 * @return a handle to the master Atom event feed (<i>not</i> the per-run
+	 *         feed)
+	 */
+	EventDAO getMasterEventFeed();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PasswordIssuer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PasswordIssuer.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PasswordIssuer.java
new file mode 100644
index 0000000..649db64
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PasswordIssuer.java
@@ -0,0 +1,73 @@
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A simple password issuing bean.
+ * 
+ * @author Donal Fellows
+ */
+public class PasswordIssuer {
+	private static final char[] ALPHABET = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+			'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+			'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+			'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+			'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7',
+			'8', '9', '0', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+			',', '.', '<', '>', '/', '?', ':', ';', '-', '_', '+', '[', ']',
+			'{', '}', '`', '~' };
+	private Log log = LogFactory.getLog("Taverna.Server.Worker");
+	private SecureRandom r;
+	private int length;
+
+	public PasswordIssuer() {
+		r = new SecureRandom();
+		log.info("constructing passwords with " + r.getAlgorithm());
+		setLength(8);
+	}
+
+	public PasswordIssuer(String algorithm) throws NoSuchAlgorithmException {
+		r = SecureRandom.getInstance(algorithm);
+		log.info("constructing passwords with " + r.getAlgorithm());
+		setLength(8);
+	}
+
+	public void setLength(int length) {
+		this.length = length;
+		log.info("issued password will be " + this.length
+				+ " symbols chosen from " + ALPHABET.length);
+	}
+
+	/**
+	 * Issue a password.
+	 * 
+	 * @return The new password.
+	 */
+	public String issue() {
+		StringBuilder sb = new StringBuilder();
+		for (int i = 0; i < length; i++)
+			sb.append(ALPHABET[r.nextInt(ALPHABET.length)]);
+		log.info("issued new password of length " + sb.length());
+		return sb.toString();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyImpl.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyImpl.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyImpl.java
new file mode 100644
index 0000000..37d5760
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyImpl.java
@@ -0,0 +1,171 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.taverna.server.master.common.Roles;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Basic policy implementation that allows any workflow to be instantiated by
+ * any user, but which does not permit users to access each others workflow
+ * runs. It also imposes a global limit on the number of workflow runs at once.
+ * 
+ * @author Donal Fellows
+ */
+class PolicyImpl implements Policy {
+	Log log = LogFactory.getLog("Taverna.Server.Worker.Policy");
+	private PolicyLimits limits;
+	private RunDBSupport runDB;
+
+	@Required
+	public void setLimits(PolicyLimits limits) {
+		this.limits = limits;
+	}
+
+	@Required
+	public void setRunDB(RunDBSupport runDB) {
+		this.runDB = runDB;
+	}
+
+	@Override
+	public int getMaxRuns() {
+		return limits.getMaxRuns();
+	}
+
+	@Override
+	public Integer getMaxRuns(UsernamePrincipal user) {
+		return null;
+	}
+
+	@Override
+	public int getOperatingLimit() {
+		return limits.getOperatingLimit();
+	}
+
+	@Override
+	public List<URI> listPermittedWorkflowURIs(UsernamePrincipal user) {
+		return limits.getPermittedWorkflowURIs();
+	}
+
+	private boolean isSelfAccess(String runId) {
+		Authentication auth = SecurityContextHolder.getContext()
+				.getAuthentication();
+		boolean self = false;
+		String id = null;
+		for (GrantedAuthority a : auth.getAuthorities()) {
+			String aa = a.getAuthority();
+			if (aa.equals(Roles.SELF)) {
+				self = true;
+				continue;
+			}
+			if (!aa.startsWith(PREFIX))
+				continue;
+			id = aa.substring(PREFIX.length());
+		}
+		return self && runId.equals(id);
+	}
+
+	@Override
+	public boolean permitAccess(UsernamePrincipal user, TavernaRun run) {
+		String username = user.getName();
+		TavernaSecurityContext context = run.getSecurityContext();
+		if (context.getOwner().getName().equals(username)) {
+			if (log.isDebugEnabled())
+				log.debug("granted access by " + user.getName() + " to "
+						+ run.getId());
+			return true;
+		}
+		if (isSelfAccess(run.getId())) {
+			if (log.isDebugEnabled())
+				log.debug("access by workflow to itself: " + run.getId());
+			return true;
+		}
+		if (log.isDebugEnabled())
+			log.debug("considering access by " + user.getName() + " to "
+					+ run.getId());
+		return context.getPermittedReaders().contains(username);
+	}
+
+	@Override
+	public void permitCreate(UsernamePrincipal user, Workflow workflow)
+			throws NoCreateException {
+		if (user == null)
+			throw new NoCreateException(
+					"anonymous workflow creation not allowed");
+		if (runDB.countRuns() >= getMaxRuns())
+			throw new NoCreateException("server load exceeded; please wait");
+	}
+
+	@Override
+	public synchronized void permitDestroy(UsernamePrincipal user, TavernaRun run)
+			throws NoDestroyException {
+		if (user == null)
+			throw new NoDestroyException();
+		String username = user.getName();
+		TavernaSecurityContext context = run.getSecurityContext();
+		if (context.getOwner() == null
+				|| context.getOwner().getName().equals(username))
+			return;
+		if (!context.getPermittedDestroyers().contains(username))
+			throw new NoDestroyException();
+	}
+
+	@Override
+	public void permitUpdate(UsernamePrincipal user, TavernaRun run)
+			throws NoUpdateException {
+		if (user == null)
+			throw new NoUpdateException(
+					"workflow run not owned by you and you're not granted access");
+		TavernaSecurityContext context = run.getSecurityContext();
+		if (context.getOwner().getName().equals(user.getName()))
+			return;
+		if (isSelfAccess(run.getId())) {
+			if (log.isDebugEnabled())
+				log.debug("update access by workflow to itself: " + run.getId());
+			return;
+		}
+		if (!context.getPermittedUpdaters().contains(user.getName()))
+			throw new NoUpdateException(
+					"workflow run not owned by you and you're not granted access");
+	}
+
+	@Override
+	public void setPermittedWorkflowURIs(UsernamePrincipal user,
+			List<URI> permitted) {
+		limits.setPermittedWorkflowURIs(permitted);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyLimits.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyLimits.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyLimits.java
new file mode 100644
index 0000000..43c0aa4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/PolicyLimits.java
@@ -0,0 +1,56 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import java.net.URI;
+import java.util.List;
+
+import org.taverna.server.master.common.Status;
+
+/**
+ * The worker policy delegates certain limits to the state model of the
+ * particular worker.
+ * 
+ * @author Donal Fellows
+ */
+public interface PolicyLimits {
+	/**
+	 * @return the maximum number of extant workflow runs in any state
+	 */
+	int getMaxRuns();
+
+	/**
+	 * @return the maximum number of workflow runs in the
+	 *         {@linkplain Status#Operating operating} state.
+	 */
+	int getOperatingLimit();
+
+	/**
+	 * @return the list of URIs to workflows that may be used to create workflow
+	 *         runs. If empty or <tt>null</tt>, no restriction is present.
+	 */
+	List<URI> getPermittedWorkflowURIs();
+
+	/**
+	 * @param permitted
+	 *            the list of URIs to workflows that may be used to create
+	 *            workflow runs.
+	 */
+	void setPermittedWorkflowURIs(List<URI> permitted);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RemoteRunDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RemoteRunDelegate.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RemoteRunDelegate.java
new file mode 100644
index 0000000..fb1ac47
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RemoteRunDelegate.java
@@ -0,0 +1,980 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static java.lang.System.currentTimeMillis;
+import static java.util.Calendar.MINUTE;
+import static java.util.Collections.sort;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.UUID.randomUUID;
+import static org.apache.commons.io.IOUtils.closeQuietly;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.worker.RemoteRunDelegate.checkBadFilename;
+import static org.taverna.server.master.worker.RunConnection.NAME_LENGTH;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PipedOutputStream;
+import java.rmi.MarshalledObject;
+import java.rmi.RemoteException;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.logging.Log;
+import org.taverna.server.localworker.remote.IllegalStateTransitionException;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
+import org.taverna.server.localworker.remote.RemoteFile;
+import org.taverna.server.localworker.remote.RemoteInput;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.remote.StillWorkingOnItException;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.OverloadedException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.Input;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.SecurityContextFactory;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Bridging shim between the WebApp world and the RMI world.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+public class RemoteRunDelegate implements TavernaRun {
+	private transient Log log = getLog("Taverna.Server.Worker");
+	transient TavernaSecurityContext secContext;
+	Date creationInstant;
+	Workflow workflow;
+	Date expiry;
+	HashSet<String> readers;
+	HashSet<String> writers;
+	HashSet<String> destroyers;
+	transient String id;
+	transient RemoteSingleRun run;
+	transient RunDBSupport db;
+	transient FactoryBean factory;
+	boolean doneTransitionToFinished;
+	boolean generateProvenance;// FIXME expose
+	String name;
+	private static final String ELLIPSIS = "...";
+
+	public RemoteRunDelegate(Date creationInstant, Workflow workflow,
+			RemoteSingleRun rsr, int defaultLifetime, RunDBSupport db, UUID id,
+			boolean generateProvenance, FactoryBean factory) {
+		if (rsr == null)
+			throw new IllegalArgumentException("remote run must not be null");
+		this.creationInstant = creationInstant;
+		this.workflow = workflow;
+		Calendar c = Calendar.getInstance();
+		c.add(MINUTE, defaultLifetime);
+		this.expiry = c.getTime();
+		this.run = rsr;
+		this.db = db;
+		this.generateProvenance = generateProvenance;
+		this.factory = factory;
+		try {
+			this.name = "";
+			String ci = " " + creationInstant;
+			String n = workflow.getName();
+			if (n.length() > NAME_LENGTH - ci.length())
+				n = n.substring(0,
+						NAME_LENGTH - ci.length() - ELLIPSIS.length())
+						+ ELLIPSIS;
+			this.name = n + ci;
+		} catch (Exception e) {
+			// Ignore; it's just a name, not something important.
+		}
+		if (id != null)
+			this.id = id.toString();
+	}
+
+	RemoteRunDelegate() {
+	}
+
+	/**
+	 * Get the types of listener supported by this run.
+	 * 
+	 * @return A list of listener type names.
+	 * @throws RemoteException
+	 *             If anything goes wrong.
+	 */
+	public List<String> getListenerTypes() throws RemoteException {
+		return run.getListenerTypes();
+	}
+
+	@Override
+	public void addListener(Listener listener) {
+		if (listener instanceof ListenerDelegate)
+			try {
+				run.addListener(((ListenerDelegate) listener).getRemote());
+			} catch (RemoteException e) {
+				log.warn("communication problem adding listener", e);
+			} catch (ImplementationException e) {
+				log.warn("implementation problem adding listener", e);
+			}
+		else
+			log.fatal("bad listener " + listener.getClass()
+					+ "; not applicable remotely!");
+	}
+
+	@Override
+	public String getId() {
+		if (id == null)
+			id = randomUUID().toString();
+		return id;
+	}
+
+	/**
+	 * Attach a listener to a workflow run and return its local delegate.
+	 * 
+	 * @param type
+	 *            The type of listener to create.
+	 * @param config
+	 *            The configuration of the listener.
+	 * @return The local delegate of the listener.
+	 * @throws NoListenerException
+	 *             If anything goes wrong.
+	 */
+	public Listener makeListener(String type, String config)
+			throws NoListenerException {
+		try {
+			return new ListenerDelegate(run.makeListener(type, config));
+		} catch (RemoteException e) {
+			throw new NoListenerException("failed to make listener", e);
+		}
+	}
+
+	@Override
+	public void destroy() {
+		try {
+			run.destroy();
+		} catch (RemoteException | ImplementationException e) {
+			log.warn("failed to destroy run", e);
+		}
+	}
+
+	@Override
+	public Date getExpiry() {
+		return new Date(expiry.getTime());
+	}
+
+	@Override
+	public List<Listener> getListeners() {
+		List<Listener> listeners = new ArrayList<>();
+		try {
+			for (RemoteListener rl : run.getListeners())
+				listeners.add(new ListenerDelegate(rl));
+		} catch (RemoteException e) {
+			log.warn("failed to get listeners", e);
+		}
+		return listeners;
+	}
+
+	@Override
+	public TavernaSecurityContext getSecurityContext() {
+		return secContext;
+	}
+
+	@Override
+	public Status getStatus() {
+		try {
+			switch (run.getStatus()) {
+			case Initialized:
+				return Status.Initialized;
+			case Operating:
+				return Status.Operating;
+			case Stopped:
+				return Status.Stopped;
+			case Finished:
+				return Status.Finished;
+			}
+		} catch (RemoteException e) {
+			log.warn("problem getting remote status", e);
+		}
+		return Status.Finished;
+	}
+
+	@Override
+	public Workflow getWorkflow() {
+		return workflow;
+	}
+
+	@Override
+	public Directory getWorkingDirectory() throws FilesystemAccessException {
+		try {
+			return new DirectoryDelegate(run.getWorkingDirectory());
+		} catch (Throwable e) {
+			if (e.getCause() != null)
+				e = e.getCause();
+			throw new FilesystemAccessException(
+					"problem getting main working directory handle", e);
+		}
+	}
+
+	@Override
+	public void setExpiry(Date d) {
+		if (d.after(new Date()))
+			expiry = new Date(d.getTime());
+		db.flushToDisk(this);
+	}
+
+	@Override
+	public String setStatus(Status s) throws BadStateChangeException {
+		try {
+			log.info("setting status of run " + id + " to " + s);
+			switch (s) {
+			case Initialized:
+				run.setStatus(RemoteStatus.Initialized);
+				break;
+			case Operating:
+				if (run.getStatus() == RemoteStatus.Initialized) {
+					if (!factory.isAllowingRunsToStart())
+						throw new OverloadedException();
+					secContext.conveySecurity();
+				}
+				run.setGenerateProvenance(generateProvenance);
+				run.setStatus(RemoteStatus.Operating);
+				factory.getMasterEventFeed()
+						.started(
+								this,
+								"started run execution",
+								"The execution of run '" + getName()
+										+ "' has started.");
+				break;
+			case Stopped:
+				run.setStatus(RemoteStatus.Stopped);
+				break;
+			case Finished:
+				run.setStatus(RemoteStatus.Finished);
+				break;
+			}
+			return null;
+		} catch (IllegalStateTransitionException e) {
+			throw new BadStateChangeException(e.getMessage());
+		} catch (RemoteException e) {
+			throw new BadStateChangeException(e.getMessage(), e.getCause());
+		} catch (GeneralSecurityException | IOException e) {
+			throw new BadStateChangeException(e.getMessage(), e);
+		} catch (ImplementationException e) {
+			if (e.getCause() != null)
+				throw new BadStateChangeException(e.getMessage(), e.getCause());
+			throw new BadStateChangeException(e.getMessage(), e);
+		} catch (StillWorkingOnItException e) {
+			log.info("still working on setting status of run " + id + " to "
+					+ s, e);
+			return e.getMessage();
+		} catch (InterruptedException e) {
+			throw new BadStateChangeException(
+					"interrupted while waiting to insert notification into database");
+		}
+	}
+
+	static void checkBadFilename(String filename)
+			throws FilesystemAccessException {
+		if (filename.startsWith("/"))
+			throw new FilesystemAccessException("filename may not be absolute");
+		if (Arrays.asList(filename.split("/")).contains(".."))
+			throw new FilesystemAccessException(
+					"filename may not refer to parent");
+	}
+
+	@Override
+	public String getInputBaclavaFile() {
+		try {
+			return run.getInputBaclavaFile();
+		} catch (RemoteException e) {
+			log.warn("problem when fetching input baclava file", e);
+			return null;
+		}
+	}
+
+	@Override
+	public List<Input> getInputs() {
+		ArrayList<Input> inputs = new ArrayList<>();
+		try {
+			for (RemoteInput ri : run.getInputs())
+				inputs.add(new RunInput(ri));
+		} catch (RemoteException e) {
+			log.warn("problem when fetching list of workflow inputs", e);
+		}
+		return inputs;
+	}
+
+	@Override
+	public String getOutputBaclavaFile() {
+		try {
+			return run.getOutputBaclavaFile();
+		} catch (RemoteException e) {
+			log.warn("problem when fetching output baclava file", e);
+			return null;
+		}
+	}
+
+	@Override
+	public Input makeInput(String name) throws BadStateChangeException {
+		try {
+			return new RunInput(run.makeInput(name));
+		} catch (RemoteException e) {
+			throw new BadStateChangeException("failed to make input", e);
+		}
+	}
+
+	@Override
+	public void setInputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException {
+		checkBadFilename(filename);
+		try {
+			run.setInputBaclavaFile(filename);
+		} catch (RemoteException e) {
+			throw new FilesystemAccessException(
+					"cannot set input baclava file name", e);
+		}
+	}
+
+	@Override
+	public void setOutputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException {
+		checkBadFilename(filename);
+		try {
+			run.setOutputBaclavaFile(filename);
+		} catch (RemoteException e) {
+			throw new FilesystemAccessException(
+					"cannot set output baclava file name", e);
+		}
+	}
+
+	@Override
+	public Date getCreationTimestamp() {
+		return creationInstant == null ? null : new Date(
+				creationInstant.getTime());
+	}
+
+	@Override
+	public Date getFinishTimestamp() {
+		try {
+			return run.getFinishTimestamp();
+		} catch (RemoteException e) {
+			log.info("failed to get finish timestamp", e);
+			return null;
+		}
+	}
+
+	@Override
+	public Date getStartTimestamp() {
+		try {
+			return run.getStartTimestamp();
+		} catch (RemoteException e) {
+			log.info("failed to get finish timestamp", e);
+			return null;
+		}
+	}
+
+	/**
+	 * @param readers
+	 *            the readers to set
+	 */
+	public void setReaders(Set<String> readers) {
+		this.readers = new HashSet<>(readers);
+		db.flushToDisk(this);
+	}
+
+	/**
+	 * @return the readers
+	 */
+	public Set<String> getReaders() {
+		return readers == null ? new HashSet<String>()
+				: unmodifiableSet(readers);
+	}
+
+	/**
+	 * @param writers
+	 *            the writers to set
+	 */
+	public void setWriters(Set<String> writers) {
+		this.writers = new HashSet<>(writers);
+		db.flushToDisk(this);
+	}
+
+	/**
+	 * @return the writers
+	 */
+	public Set<String> getWriters() {
+		return writers == null ? new HashSet<String>()
+				: unmodifiableSet(writers);
+	}
+
+	/**
+	 * @param destroyers
+	 *            the destroyers to set
+	 */
+	public void setDestroyers(Set<String> destroyers) {
+		this.destroyers = new HashSet<>(destroyers);
+		db.flushToDisk(this);
+	}
+
+	/**
+	 * @return the destroyers
+	 */
+	public Set<String> getDestroyers() {
+		return destroyers == null ? new HashSet<String>()
+				: unmodifiableSet(destroyers);
+	}
+
+	private void writeObject(ObjectOutputStream out) throws IOException {
+		out.defaultWriteObject();
+		out.writeUTF(secContext.getOwner().getName());
+		out.writeObject(secContext.getFactory());
+		out.writeObject(new MarshalledObject<>(run));
+	}
+
+	@Override
+	public boolean getGenerateProvenance() {
+		return generateProvenance;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean generateProvenance) {
+		this.generateProvenance = generateProvenance;
+		db.flushToDisk(this);
+	}
+
+	@SuppressWarnings("unchecked")
+	private void readObject(ObjectInputStream in) throws IOException,
+			ClassNotFoundException {
+		in.defaultReadObject();
+		if (log == null)
+			log = getLog("Taverna.Server.LocalWorker");
+		final String creatorName = in.readUTF();
+		SecurityContextFactory factory = (SecurityContextFactory) in
+				.readObject();
+		try {
+			secContext = factory.create(this,
+					new UsernamePrincipal(creatorName));
+		} catch (RuntimeException | IOException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new SecurityContextReconstructionException(e);
+		}
+		run = ((MarshalledObject<RemoteSingleRun>) in.readObject()).get();
+	}
+
+	public void setSecurityContext(TavernaSecurityContext tavernaSecurityContext) {
+		secContext = tavernaSecurityContext;
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public void setName(@Nonnull String name) {
+		if (name.length() > RunConnection.NAME_LENGTH)
+			this.name = name.substring(0, RunConnection.NAME_LENGTH);
+		else
+			this.name = name;
+		db.flushToDisk(this);
+	}
+
+	@Override
+	public void ping() throws UnknownRunException {
+		try {
+			run.ping();
+		} catch (RemoteException e) {
+			throw new UnknownRunException(e);
+		}
+	}
+}
+
+abstract class DEDelegate implements DirectoryEntry {
+	Log log = getLog("Taverna.Server.Worker");
+	private RemoteDirectoryEntry entry;
+	private String name;
+	private String full;
+	private Date cacheModTime;
+	private long cacheQueryTime = 0L;
+
+	DEDelegate(RemoteDirectoryEntry entry) {
+		this.entry = entry;
+	}
+
+	@Override
+	public void destroy() throws FilesystemAccessException {
+		try {
+			entry.destroy();
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"failed to delete directory entry", e);
+		}
+	}
+
+	@Override
+	public String getFullName() {
+		if (full != null)
+			return full;
+		String n = getName();
+		RemoteDirectoryEntry re = entry;
+		try {
+			while (true) {
+				RemoteDirectory parent = re.getContainingDirectory();
+				if (parent == null)
+					break;
+				n = parent.getName() + "/" + n;
+				re = parent;
+			}
+		} catch (RemoteException e) {
+			log.warn("failed to generate full name", e);
+		}
+		return (full = n);
+	}
+
+	@Override
+	public String getName() {
+		if (name == null)
+			try {
+				name = entry.getName();
+			} catch (RemoteException e) {
+				log.error("failed to get name", e);
+			}
+		return name;
+	}
+
+	@Override
+	public Date getModificationDate() {
+		if (cacheModTime == null || currentTimeMillis() - cacheQueryTime < 5000)
+			try {
+				cacheModTime = entry.getModificationDate();
+				cacheQueryTime = currentTimeMillis();
+			} catch (RemoteException e) {
+				log.error("failed to get modification time", e);
+			}
+		return cacheModTime;
+	}
+
+	@Override
+	public int compareTo(DirectoryEntry de) {
+		return getFullName().compareTo(de.getFullName());
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		return o != null && o instanceof DEDelegate
+				&& getFullName().equals(((DEDelegate) o).getFullName());
+	}
+
+	@Override
+	public int hashCode() {
+		return getFullName().hashCode();
+	}
+}
+
+class DirectoryDelegate extends DEDelegate implements Directory {
+	RemoteDirectory rd;
+
+	DirectoryDelegate(RemoteDirectory dir) {
+		super(dir);
+		rd = dir;
+	}
+
+	@Override
+	public Collection<DirectoryEntry> getContents()
+			throws FilesystemAccessException {
+		ArrayList<DirectoryEntry> result = new ArrayList<>();
+		try {
+			for (RemoteDirectoryEntry rde : rd.getContents()) {
+				if (rde instanceof RemoteDirectory)
+					result.add(new DirectoryDelegate((RemoteDirectory) rde));
+				else
+					result.add(new FileDelegate((RemoteFile) rde));
+			}
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"failed to get directory contents", e);
+		}
+		return result;
+	}
+
+	@Override
+	public Collection<DirectoryEntry> getContentsByDate()
+			throws FilesystemAccessException {
+		ArrayList<DirectoryEntry> result = new ArrayList<>(getContents());
+		sort(result, new DateComparator());
+		return result;
+	}
+
+	static class DateComparator implements Comparator<DirectoryEntry> {
+		@Override
+		public int compare(DirectoryEntry a, DirectoryEntry b) {
+			return a.getModificationDate().compareTo(b.getModificationDate());
+		}
+	}
+
+	@Override
+	public File makeEmptyFile(Principal actor, String name)
+			throws FilesystemAccessException {
+		try {
+			return new FileDelegate(rd.makeEmptyFile(name));
+		} catch (IOException e) {
+			throw new FilesystemAccessException("failed to make empty file", e);
+		}
+	}
+
+	@Override
+	public Directory makeSubdirectory(Principal actor, String name)
+			throws FilesystemAccessException {
+		try {
+			return new DirectoryDelegate(rd.makeSubdirectory(name));
+		} catch (IOException e) {
+			throw new FilesystemAccessException("failed to make subdirectory",
+					e);
+		}
+	}
+
+	@Override
+	public ZipStream getContentsAsZip() throws FilesystemAccessException {
+		ZipStream zs = new ZipStream();
+
+		final ZipOutputStream zos;
+		try {
+			zos = new ZipOutputStream(new PipedOutputStream(zs));
+		} catch (IOException e) {
+			throw new FilesystemAccessException("problem building zip stream",
+					e);
+		}
+		Thread t = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					zipDirectory(rd, null, zos);
+				} catch (IOException e) {
+					log.warn("problem when zipping directory", e);
+				} finally {
+					closeQuietly(zos);
+				}
+			}
+		});
+		t.setDaemon(true);
+		t.start();
+		return zs;
+	}
+
+	/**
+	 * Compresses a directory tree into a ZIP.
+	 * 
+	 * @param dir
+	 *            The directory to compress.
+	 * @param base
+	 *            The base name of the directory (or <tt>null</tt> if this is
+	 *            the root directory of the ZIP).
+	 * @param zos
+	 *            Where to write the compressed data.
+	 * @throws RemoteException
+	 *             If some kind of problem happens with the remote delegates.
+	 * @throws IOException
+	 *             If we run into problems with reading or writing data.
+	 */
+	void zipDirectory(RemoteDirectory dir, String base, ZipOutputStream zos)
+			throws RemoteException, IOException {
+		for (RemoteDirectoryEntry rde : dir.getContents()) {
+			String name = rde.getName();
+			if (base != null)
+				name = base + "/" + name;
+			if (rde instanceof RemoteDirectory) {
+				RemoteDirectory rd = (RemoteDirectory) rde;
+				zipDirectory(rd, name, zos);
+			} else {
+				RemoteFile rf = (RemoteFile) rde;
+				zos.putNextEntry(new ZipEntry(name));
+				try {
+					int off = 0;
+					while (true) {
+						byte[] c = rf.getContents(off, 64 * 1024);
+						if (c == null || c.length == 0)
+							break;
+						zos.write(c);
+						off += c.length;
+					}
+				} finally {
+					zos.closeEntry();
+				}
+			}
+		}
+	}
+}
+
+class FileDelegate extends DEDelegate implements File {
+	RemoteFile rf;
+
+	FileDelegate(RemoteFile f) {
+		super(f);
+		this.rf = f;
+	}
+
+	@Override
+	public byte[] getContents(int offset, int length)
+			throws FilesystemAccessException {
+		try {
+			return rf.getContents(offset, length);
+		} catch (IOException e) {
+			throw new FilesystemAccessException("failed to read file contents",
+					e);
+		}
+	}
+
+	@Override
+	public long getSize() throws FilesystemAccessException {
+		try {
+			return rf.getSize();
+		} catch (IOException e) {
+			throw new FilesystemAccessException("failed to get file length", e);
+		}
+	}
+
+	@Override
+	public void setContents(byte[] data) throws FilesystemAccessException {
+		try {
+			rf.setContents(data);
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"failed to write file contents", e);
+		}
+	}
+
+	@Override
+	public void appendContents(byte[] data) throws FilesystemAccessException {
+		try {
+			rf.appendContents(data);
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"failed to write file contents", e);
+		}
+	}
+
+	@Override
+	public void copy(File from) throws FilesystemAccessException {
+		FileDelegate fromFile;
+		try {
+			fromFile = (FileDelegate) from;
+		} catch (ClassCastException e) {
+			throw new FilesystemAccessException("different types of File?!");
+		}
+
+		try {
+			rf.copy(fromFile.rf);
+		} catch (Exception e) {
+			throw new FilesystemAccessException("failed to copy file contents",
+					e);
+		}
+		return;
+	}
+}
+
+class ListenerDelegate implements Listener {
+	private Log log = getLog("Taverna.Server.Worker");
+	private RemoteListener r;
+	String conf;
+
+	ListenerDelegate(RemoteListener l) {
+		r = l;
+	}
+
+	RemoteListener getRemote() {
+		return r;
+	}
+
+	@Override
+	public String getConfiguration() {
+		try {
+			if (conf == null)
+				conf = r.getConfiguration();
+		} catch (RemoteException e) {
+			log.warn("failed to get configuration", e);
+		}
+		return conf;
+	}
+
+	@Override
+	public String getName() {
+		try {
+			return r.getName();
+		} catch (RemoteException e) {
+			log.warn("failed to get name", e);
+			return "UNKNOWN NAME";
+		}
+	}
+
+	@Override
+	public String getProperty(String propName) throws NoListenerException {
+		try {
+			return r.getProperty(propName);
+		} catch (RemoteException e) {
+			throw new NoListenerException("no such property: " + propName, e);
+		}
+	}
+
+	@Override
+	public String getType() {
+		try {
+			return r.getType();
+		} catch (RemoteException e) {
+			log.warn("failed to get type", e);
+			return "UNKNOWN TYPE";
+		}
+	}
+
+	@Override
+	public String[] listProperties() {
+		try {
+			return r.listProperties();
+		} catch (RemoteException e) {
+			log.warn("failed to list properties", e);
+			return new String[0];
+		}
+	}
+
+	@Override
+	public void setProperty(String propName, String value)
+			throws NoListenerException, BadPropertyValueException {
+		try {
+			r.setProperty(propName, value);
+		} catch (RemoteException e) {
+			log.warn("failed to set property", e);
+			if (e.getCause() != null
+					&& e.getCause() instanceof RuntimeException)
+				throw new NoListenerException("failed to set property",
+						e.getCause());
+			if (e.getCause() != null && e.getCause() instanceof Exception)
+				throw new BadPropertyValueException("failed to set property",
+						e.getCause());
+			throw new BadPropertyValueException("failed to set property", e);
+		}
+	}
+}
+
+class RunInput implements Input {
+	private final RemoteInput i;
+
+	RunInput(RemoteInput remote) {
+		this.i = remote;
+	}
+
+	@Override
+	public String getFile() {
+		try {
+			return i.getFile();
+		} catch (RemoteException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public String getName() {
+		try {
+			return i.getName();
+		} catch (RemoteException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public String getValue() {
+		try {
+			return i.getValue();
+		} catch (RemoteException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public void setFile(String file) throws FilesystemAccessException,
+			BadStateChangeException {
+		checkBadFilename(file);
+		try {
+			i.setFile(file);
+		} catch (RemoteException e) {
+			throw new FilesystemAccessException("cannot set file for input", e);
+		}
+	}
+
+	@Override
+	public void setValue(String value) throws BadStateChangeException {
+		try {
+			i.setValue(value);
+		} catch (RemoteException e) {
+			throw new BadStateChangeException(e);
+		}
+	}
+
+	@Override
+	public String getDelimiter() {
+		try {
+			return i.getDelimiter();
+		} catch (RemoteException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public void setDelimiter(String delimiter) throws BadStateChangeException {
+		try {
+			if (delimiter != null)
+				delimiter = delimiter.substring(0, 1);
+			i.setDelimiter(delimiter);
+		} catch (RemoteException e) {
+			throw new BadStateChangeException(e);
+		}
+	}
+}
+
+@SuppressWarnings("serial")
+class SecurityContextReconstructionException extends RuntimeException {
+	public SecurityContextReconstructionException(Throwable t) {
+		super("failed to rebuild security context", t);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunConnection.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunConnection.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunConnection.java
new file mode 100644
index 0000000..0c2b1a9
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunConnection.java
@@ -0,0 +1,252 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static org.taverna.server.master.worker.RunConnection.COUNT_QUERY;
+import static org.taverna.server.master.worker.RunConnection.NAMES_QUERY;
+import static org.taverna.server.master.worker.RunConnection.SCHEMA;
+import static org.taverna.server.master.worker.RunConnection.TABLE;
+import static org.taverna.server.master.worker.RunConnection.TIMEOUT_QUERY;
+import static org.taverna.server.master.worker.RunConnection.UNTERMINATED_QUERY;
+
+import java.io.IOException;
+import java.rmi.MarshalledObject;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.jdo.annotations.Column;
+import javax.jdo.annotations.Join;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.PrimaryKey;
+import javax.jdo.annotations.Queries;
+import javax.jdo.annotations.Query;
+
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.interfaces.SecurityContextFactory;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * The representation of the connections to the runs that actually participates
+ * in the persistence system.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceCapable(table = TABLE, schema = SCHEMA)
+@Queries({
+		@Query(name = "count", language = "SQL", value = COUNT_QUERY, unique = "true", resultClass = Integer.class),
+		@Query(name = "names", language = "SQL", value = NAMES_QUERY, unique = "false", resultClass = String.class),
+		@Query(name = "unterminated", language = "SQL", value = UNTERMINATED_QUERY, unique = "false", resultClass = String.class),
+		@Query(name = "timedout", language = "SQL", value = TIMEOUT_QUERY, unique = "false", resultClass = String.class) })
+public class RunConnection {
+	static final String SCHEMA = "TAVERNA";
+	static final String TABLE = "RUN_CONNECTION";
+	private static final String FULL_NAME = SCHEMA + "." + TABLE;
+	static final String COUNT_QUERY = "SELECT count(*) FROM " + FULL_NAME;
+	static final String NAMES_QUERY = "SELECT ID FROM " + FULL_NAME;
+	static final String TIMEOUT_QUERY = "SELECT ID FROM " + FULL_NAME
+			+ "   WHERE expiry < CURRENT_TIMESTAMP";
+	static final String UNTERMINATED_QUERY = "SELECT ID FROM " + FULL_NAME
+			+ "   WHERE doneTransitionToFinished = 0";
+	static final int NAME_LENGTH = 48; 
+
+	@PrimaryKey
+	@Column(length = 40)
+	private String id;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Column(length = NAME_LENGTH)
+	private String name;
+
+	@Persistent(defaultFetchGroup = "true")
+	private Date creationInstant;
+
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private Workflow workflow;
+
+	@Persistent(defaultFetchGroup = "true")
+	private Date expiry;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Join(table = TABLE + "_READERS", column = "ID")
+	private String[] readers;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Join(table = TABLE + "_WRITERS", column = "ID")
+	private String[] writers;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Join(table = TABLE + "_DESTROYERS", column = "ID")
+	private String[] destroyers;
+
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private MarshalledObject<RemoteSingleRun> run;
+
+	@Persistent(defaultFetchGroup = "true")
+	private int doneTransitionToFinished;
+
+	@Persistent(defaultFetchGroup = "true")
+	private int generateProvenance;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Column(length = 128)
+	String owner;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Column(length = 36)
+	private String securityToken;
+
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private SecurityContextFactory securityContextFactory;
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private Credential[] credentials;
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private Trust[] trust;
+
+	private static final String[] STRING_ARY = new String[0];
+
+	public String getId() {
+		return id;
+	}
+
+	public boolean isFinished() {
+		return doneTransitionToFinished != 0;
+	}
+
+	public void setFinished(boolean finished) {
+		doneTransitionToFinished = (finished ? 1 : 0);
+	}
+
+	public boolean isProvenanceGenerated() {
+		return generateProvenance != 0;
+	}
+
+	public void setProvenanceGenerated(boolean generate) {
+		generateProvenance = (generate ? 1 : 0);
+	}
+
+	/**
+	 * Manufacture a persistent representation of the given workflow run. Must
+	 * be called within the context of a transaction.
+	 * 
+	 * @param rrd
+	 *            The remote delegate of the workflow run.
+	 * @return The persistent object.
+	 * @throws IOException
+	 *             If serialisation fails.
+	 */
+	@Nonnull
+	public static RunConnection toDBform(@Nonnull RemoteRunDelegate rrd)
+			throws IOException {
+		RunConnection rc = new RunConnection();
+		rc.id = rrd.id;
+		rc.makeChanges(rrd);
+		return rc;
+	}
+
+	private static List<String> list(String[] ary) {
+		if (ary == null)
+			return emptyList();
+		return asList(ary);
+	}
+
+	/**
+	 * Get the remote run delegate for a particular persistent connection. Must
+	 * be called within the context of a transaction.
+	 * 
+	 * @param db
+	 *            The database facade.
+	 * @return The delegate object.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	@Nonnull
+	public RemoteRunDelegate fromDBform(@Nonnull RunDBSupport db)
+			throws Exception {
+		RemoteRunDelegate rrd = new RemoteRunDelegate();
+		rrd.id = getId();
+		rrd.creationInstant = creationInstant;
+		rrd.workflow = workflow;
+		rrd.expiry = expiry;
+		rrd.readers = new HashSet<>(list(readers));
+		rrd.writers = new HashSet<>(list(writers));
+		rrd.destroyers = new HashSet<>(list(destroyers));
+		rrd.run = run.get();
+		rrd.doneTransitionToFinished = isFinished();
+		rrd.generateProvenance = isProvenanceGenerated();
+		rrd.secContext = securityContextFactory.create(rrd,
+				new UsernamePrincipal(owner));
+		((SecurityContextDelegate)rrd.secContext).setCredentialsAndTrust(credentials,trust);
+		rrd.db = db;
+		rrd.factory = db.getFactory();
+		rrd.name = name;
+		return rrd;
+	}
+
+	/**
+	 * Flush changes from a remote run delegate to the database. Must be called
+	 * within the context of a transaction.
+	 * 
+	 * @param rrd
+	 *            The remote run delegate object that has potential changes.
+	 * @throws IOException
+	 *             If anything goes wrong in serialization.
+	 */
+	public void makeChanges(@Nonnull RemoteRunDelegate rrd) throws IOException {
+		// Properties that are set exactly once
+		if (creationInstant == null) {
+			creationInstant = rrd.getCreationTimestamp();
+			workflow = rrd.getWorkflow();
+			run = new MarshalledObject<>(rrd.run);
+			securityContextFactory = rrd.getSecurityContext().getFactory();
+			owner = rrd.getSecurityContext().getOwner().getName();
+			securityToken = ((org.taverna.server.master.worker.SecurityContextFactory) securityContextFactory)
+					.issueNewPassword();
+		}
+		// Properties that are set multiple times
+		expiry = rrd.getExpiry();
+		readers = rrd.getReaders().toArray(STRING_ARY);
+		writers = rrd.getWriters().toArray(STRING_ARY);
+		destroyers = rrd.getDestroyers().toArray(STRING_ARY);
+		credentials = rrd.getSecurityContext().getCredentials();
+		trust = rrd.getSecurityContext().getTrusted();
+		if (rrd.name.length() > NAME_LENGTH)
+			this.name = rrd.name.substring(0, NAME_LENGTH);
+		else
+			this.name = rrd.name;
+		setFinished(rrd.doneTransitionToFinished);
+		setProvenanceGenerated(rrd.generateProvenance);
+	}
+
+	public String getSecurityToken() {
+		return securityToken;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDBSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDBSupport.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDBSupport.java
new file mode 100644
index 0000000..5fa96b8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDBSupport.java
@@ -0,0 +1,96 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.taverna.server.master.notification.NotificationEngine;
+
+/**
+ * The interface to the database of runs.
+ * 
+ * @author Donal Fellows
+ */
+public interface RunDBSupport {
+	/**
+	 * Scan each run to see if it has finished yet and issue registered
+	 * notifications if it has.
+	 */
+	void checkForFinishNow();
+
+	/**
+	 * Remove currently-expired runs from this database.
+	 */
+	void cleanNow();
+
+	/**
+	 * How many runs are stored in the database.
+	 * 
+	 * @return The current size of the run table.
+	 */
+	int countRuns();
+
+	/**
+	 * Ensure that a run gets persisted in the database. It is assumed that the
+	 * value is already in there.
+	 * 
+	 * @param run
+	 *            The run to persist.
+	 */
+	void flushToDisk(@Nonnull RemoteRunDelegate run);
+
+	/**
+	 * Select an arbitrary representative run.
+	 * 
+	 * @return The selected run.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	@Nullable
+	RemoteRunDelegate pickArbitraryRun() throws Exception;
+
+	/**
+	 * Get a list of all the run names.
+	 * 
+	 * @return The names (i.e., UUIDs) of all the runs.
+	 */
+	@Nonnull
+	List<String> listRunNames();
+
+	/**
+	 * @param notificationEngine
+	 *            A reference to the notification fabric bean.
+	 */
+	void setNotificationEngine(NotificationEngine notificationEngine);
+
+	/**
+	 * @param notifier
+	 *            A reference to the bean that creates messages about workflow
+	 *            run termination.
+	 */
+	void setNotifier(CompletionNotifier notifier);
+
+	/**
+	 * @return A reference to the actual factory for remote runs.
+	 */
+	FactoryBean getFactory();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabase.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabase.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabase.java
new file mode 100644
index 0000000..65aec70
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabase.java
@@ -0,0 +1,324 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static java.lang.Integer.parseInt;
+import static java.util.UUID.randomUUID;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.RunStore;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.notification.NotificationEngine;
+import org.taverna.server.master.notification.NotificationEngine.Message;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * The main facade bean that interfaces to the database of runs.
+ * 
+ * @author Donal Fellows
+ */
+public class RunDatabase implements RunStore, RunDBSupport {
+	private Log log = LogFactory.getLog("Taverna.Server.Worker.RunDB");
+	RunDatabaseDAO dao;
+	CompletionNotifier backupNotifier;
+	Map<String, CompletionNotifier> typedNotifiers;
+	private NotificationEngine notificationEngine;
+	@Autowired
+	private FactoryBean factory;
+	private Map<String, TavernaRun> cache = new HashMap<>();
+
+	@Override
+	@Required
+	public void setNotifier(CompletionNotifier n) {
+		backupNotifier = n;
+	}
+
+	public void setTypeNotifiers(List<CompletionNotifier> notifiers) {
+		typedNotifiers = new HashMap<>();
+		for (CompletionNotifier n : notifiers)
+			typedNotifiers.put(n.getName(), n);
+	}
+
+	@Required
+	@Override
+	public void setNotificationEngine(NotificationEngine notificationEngine) {
+		this.notificationEngine = notificationEngine;
+	}
+
+	@Required
+	public void setDao(RunDatabaseDAO dao) {
+		this.dao = dao;
+	}
+
+	@Override
+	public void checkForFinishNow() {
+		/*
+		 * Get which runs are actually newly finished; this requires getting the
+		 * candidates from the database and *then* doing the expensive requests
+		 * to the back end to find out the status.
+		 */
+		Map<String, RemoteRunDelegate> notifiable = new HashMap<>();
+		for (RemoteRunDelegate p : dao.getPotentiallyNotifiable())
+			if (p.getStatus() == Status.Finished)
+				notifiable.put(p.getId(), p);
+
+		// Check if there's nothing more to do
+		if (notifiable.isEmpty())
+			return;
+
+		/*
+		 * Tell the database about the ones we've got.
+		 */
+		dao.markFinished(notifiable.keySet());
+
+		/*
+		 * Send out the notifications. The notification addresses are stored in
+		 * the back-end engine, so this is *another* thing that can take time.
+		 */
+		for (RemoteRunDelegate rrd : notifiable.values())
+			for (Listener l : rrd.getListeners())
+				if (l.getName().equals("io")) {
+					try {
+						notifyFinished(rrd.id, l, rrd);
+					} catch (Exception e) {
+						log.warn("failed to do notification of completion", e);
+					}
+					break;
+				}
+	}
+
+	@Override
+	public void cleanNow() {
+		List<String> cleaned;
+		try {
+			cleaned = dao.doClean();
+		} catch (Exception e) {
+			log.warn("failure during deletion of expired runs", e);
+			return;
+		}
+		synchronized (cache) {
+			for (String id : cleaned)
+				cache.remove(id);
+		}
+	}
+
+	@Override
+	public int countRuns() {
+		return dao.countRuns();
+	}
+
+	@Override
+	public void flushToDisk(RemoteRunDelegate run) {
+		try {
+			dao.flushToDisk(run);
+		} catch (IOException e) {
+			throw new RuntimeException(
+					"unexpected problem when persisting run record in database",
+					e);
+		}
+	}
+
+	@Override
+	public RemoteRunDelegate pickArbitraryRun() throws Exception {
+		return dao.pickArbitraryRun();
+	}
+
+	@Override
+	public List<String> listRunNames() {
+		return dao.listRunNames();
+	}
+
+	@Nullable
+	private TavernaRun get(String uuid) {
+		TavernaRun run = null;
+		synchronized (cache) {
+			run = cache.get(uuid);
+		}
+		try {
+			if (run != null)
+				run.ping();
+		} catch (UnknownRunException e) {
+			if (log.isDebugEnabled())
+				log.debug("stale mapping in cache?", e);
+			// Don't need to flush the cache; this happens when cleaning anyway
+			run = null;
+		}
+		if (run == null)
+			run = dao.get(uuid);
+		return run;
+	}
+
+	@Override
+	public TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
+			throws UnknownRunException {
+		// Check first to see if the 'uuid' actually looks like a UUID; if
+		// not, throw it out immediately without logging an exception.
+		try {
+			UUID.fromString(uuid);
+		} catch (IllegalArgumentException e) {
+			if (log.isDebugEnabled())
+				log.debug("run ID does not look like UUID; rejecting...");
+			throw new UnknownRunException();
+		}
+		TavernaRun run = get(uuid);
+		if (run != null && (user == null || p.permitAccess(user, run)))
+			return run;
+		throw new UnknownRunException();
+	}
+
+	@Override
+	public TavernaRun getRun(String uuid) throws UnknownRunException {
+		TavernaRun run = get(uuid);
+		if (run != null)
+			return run;
+		throw new UnknownRunException();
+	}
+
+	@Override
+	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
+		synchronized (cache) {
+			Map<String, TavernaRun> cached = new HashMap<>();
+			for (Entry<String, TavernaRun> e : cache.entrySet()) {
+				TavernaRun r = e.getValue();
+				if (p.permitAccess(user, r))
+					cached.put(e.getKey(), r);
+			}
+			if (!cached.isEmpty())
+				return cached;
+		}
+		return dao.listRuns(user, p);
+	}
+
+	private void logLength(String message, Object obj) {
+		if (!log.isDebugEnabled())
+			return;
+		try {
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+				oos.writeObject(obj);
+			}
+			log.debug(message + ": " + baos.size());
+		} catch (Exception e) {
+			log.warn("oops", e);
+		}
+	}
+
+	@Override
+	public String registerRun(TavernaRun run) {
+		if (!(run instanceof RemoteRunDelegate))
+			throw new IllegalArgumentException(
+					"run must be created by localworker package");
+		RemoteRunDelegate rrd = (RemoteRunDelegate) run;
+		if (rrd.id == null)
+			rrd.id = randomUUID().toString();
+		logLength("RemoteRunDelegate serialized length", rrd);
+		try {
+			dao.persistRun(rrd);
+		} catch (IOException e) {
+			throw new RuntimeException(
+					"unexpected problem when persisting run record in database",
+					e);
+		}
+		synchronized (cache) {
+			cache.put(rrd.getId(), run);
+		}
+		return rrd.getId();
+	}
+
+	@Override
+	public void unregisterRun(String uuid) {
+		try {
+			if (dao.unpersistRun(uuid))
+				synchronized (cache) {
+					cache.remove(uuid);
+				}
+		} catch (RuntimeException e) {
+			if (log.isDebugEnabled())
+				log.debug("problem persisting the deletion of the run " + uuid,
+						e);
+		}
+	}
+
+	/**
+	 * Process the event that a run has finished.
+	 * 
+	 * @param name
+	 *            The name of the run.
+	 * @param io
+	 *            The io listener of the run (used to get information about the
+	 *            run).
+	 * @param run
+	 *            The handle to the run.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	private void notifyFinished(final String name, Listener io,
+			final RemoteRunDelegate run) throws Exception {
+		String to = io.getProperty("notificationAddress");
+		final int code;
+		try {
+			code = parseInt(io.getProperty("exitcode"));
+		} catch (NumberFormatException nfe) {
+			// Ignore; not much we can do here...
+			return;
+		}
+
+		notificationEngine.dispatchMessage(run, to, new Message() {
+			private CompletionNotifier getNotifier(String type) {
+				CompletionNotifier n = typedNotifiers.get(type);
+				if (n == null)
+					n = backupNotifier;
+				return n;
+			}
+
+			@Override
+			public String getContent(String type) {
+				return getNotifier(type).makeCompletionMessage(name, run, code);
+			}
+
+			@Override
+			public String getTitle(String type) {
+				return getNotifier(type).makeMessageSubject(name, run, code);
+			}
+		});
+	}
+
+	@Override
+	public FactoryBean getFactory() {
+		return factory;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabaseDAO.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabaseDAO.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabaseDAO.java
new file mode 100644
index 0000000..1c75d22
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/worker/RunDatabaseDAO.java
@@ -0,0 +1,323 @@
+/*
+ */
+package org.taverna.server.master.worker;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.worker.RunConnection.toDBform;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.jdo.annotations.PersistenceAware;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.JDOSupport;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * This handles storing runs, interfacing with the underlying state engine as
+ * necessary.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceAware
+public class RunDatabaseDAO extends JDOSupport<RunConnection> {
+	public RunDatabaseDAO() {
+		super(RunConnection.class);
+	}
+
+	private Log log = LogFactory.getLog("Taverna.Server.Worker.RunDB");
+	private RunDatabase facade;
+
+	@Required
+	public void setFacade(RunDatabase facade) {
+		this.facade = facade;
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+	@SuppressWarnings("unchecked")
+	private List<String> names() {
+		if (log.isDebugEnabled())
+			log.debug("fetching all run names");
+		return (List<String>) namedQuery("names").execute();
+	}
+
+	/**
+	 * @return The number of workflow runs in the database.
+	 */
+	@WithinSingleTransaction
+	public int countRuns() {
+		if (log.isDebugEnabled())
+			log.debug("counting the number of runs");
+		return count();
+	}
+
+	private Integer count() {
+		return (Integer) namedQuery("count").execute();
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> timedout() {
+		return (List<String>) namedQuery("timedout").execute();
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> unterminated() {
+		return (List<String>) namedQuery("unterminated").execute();
+	}
+
+	@Nullable
+	private RunConnection pickRun(@Nonnull String name) {
+		if (log.isDebugEnabled())
+			log.debug("fetching the run called " + name);
+		try {
+			RunConnection rc = getById(name);
+			if (rc == null)
+				log.warn("no result for " + name);
+			return rc;
+		} catch (RuntimeException e) {
+			log.warn("problem in fetch", e);
+			throw e;
+		}
+	}
+
+	@Nullable
+	@WithinSingleTransaction
+	public String getSecurityToken(@Nonnull String name) {
+		RunConnection rc = getById(name);
+		if (rc == null)
+			return null;
+		return rc.getSecurityToken();
+	}
+
+	private void persist(@Nonnull RemoteRunDelegate rrd) throws IOException {
+		persist(toDBform(rrd));
+	}
+
+	@Nonnull
+	private List<RunConnection> allRuns() {
+		try {
+			List<RunConnection> rcs = new ArrayList<>();
+			List<String> names = names();
+			for (String id : names) {
+				try {
+					if (id != null)
+						rcs.add(pickRun(id));
+				} catch (RuntimeException e) {
+					continue;
+				}
+			}
+			return rcs;
+		} catch (RuntimeException e) {
+			log.warn("problem in fetch", e);
+			throw e;
+		}
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+	/**
+	 * Obtain a workflow run handle.
+	 * 
+	 * @param name
+	 *            The identifier of the run.
+	 * @return The run handle, or <tt>null</tt> if there is no such run.
+	 */
+	@Nullable
+	@WithinSingleTransaction
+	public TavernaRun get(String name) {
+		try {
+			RunConnection rc = pickRun(name);
+			return (rc == null) ? null : rc.fromDBform(facade);
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/**
+	 * Get the runs that a user can read things from.
+	 * 
+	 * @param user
+	 *            Who is asking?
+	 * @param p
+	 *            The policy that determines what they can see.
+	 * @return A mapping from run IDs to run handles.
+	 */
+	@Nonnull
+	@WithinSingleTransaction
+	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
+		Map<String, TavernaRun> result = new HashMap<>();
+		for (String id : names())
+			try {
+				RemoteRunDelegate rrd = pickRun(id).fromDBform(facade);
+				if (p.permitAccess(user, rrd))
+					result.put(id, rrd);
+			} catch (Exception e) {
+				continue;
+			}
+		return result;
+	}
+
+	/**
+	 * @return A list of the IDs for all workflow runs.
+	 */
+	@Nonnull
+	@WithinSingleTransaction
+	public List<String> listRunNames() {
+		List<String> runNames = new ArrayList<>();
+		for (RunConnection rc : allRuns())
+			if (rc.getId() != null)
+				runNames.add(rc.getId());
+		return runNames;
+	}
+
+	/**
+	 * @return An arbitrary, representative workflow run.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	@Nullable
+	@WithinSingleTransaction
+	public RemoteRunDelegate pickArbitraryRun() throws Exception {
+		for (RunConnection rc : allRuns()) {
+			if (rc.getId() == null)
+				continue;
+			return rc.fromDBform(facade);
+		}
+		return null;
+	}
+
+	/**
+	 * Make a workflow run persistent. Must only be called once per workflow
+	 * run.
+	 * 
+	 * @param rrd
+	 *            The workflow run to persist.
+	 * @throws IOException
+	 *             If anything goes wrong with serialisation of the run.
+	 */
+	@WithinSingleTransaction
+	public void persistRun(@Nonnull RemoteRunDelegate rrd) throws IOException {
+		persist(rrd);
+	}
+
+	/**
+	 * Stop a workflow run from being persistent.
+	 * 
+	 * @param name
+	 *            The ID of the run.
+	 * @return Whether a deletion happened.
+	 */
+	@WithinSingleTransaction
+	public boolean unpersistRun(String name) {
+		RunConnection rc = pickRun(name);
+		if (rc != null)
+			delete(rc);
+		return rc != null;
+	}
+
+	/**
+	 * Ensure that the given workflow run is synchronized with the database.
+	 * 
+	 * @param run
+	 *            The run to synchronise.
+	 * @throws IOException
+	 *             If serialization of anything fails.
+	 */
+	@WithinSingleTransaction
+	public void flushToDisk(@Nonnull RemoteRunDelegate run) throws IOException {
+		getById(run.id).makeChanges(run);
+	}
+
+	/**
+	 * Remove all workflow runs that have expired.
+	 * 
+	 * @return The ids of the deleted runs.
+	 */
+	@Nonnull
+	@PerfLogged
+	@WithinSingleTransaction
+	public List<String> doClean() {
+		if (log.isDebugEnabled())
+			log.debug("deleting runs that timed out before " + new Date());
+		List<String> toDelete = timedout();
+		if (log.isDebugEnabled())
+			log.debug("found " + toDelete.size() + " runs to delete");
+		for (String id : toDelete) {
+			RunConnection rc = getById(id);
+			try {
+				rc.fromDBform(facade).run.destroy();
+			} catch (Exception e) {
+				if (log.isDebugEnabled())
+					log.debug("failed to delete execution resource for " + id,
+							e);
+			}
+			delete(rc);
+		}
+		return toDelete;
+	}
+
+	/**
+	 * @return A list of workflow runs that are candidates for doing
+	 *         notification of termination.
+	 */
+	@Nonnull
+	@PerfLogged
+	@WithinSingleTransaction
+	public List<RemoteRunDelegate> getPotentiallyNotifiable() {
+		List<RemoteRunDelegate> toNotify = new ArrayList<>();
+		for (String id : unterminated())
+			try {
+				RunConnection rc = getById(id);
+				toNotify.add(rc.fromDBform(facade));
+			} catch (Exception e) {
+				log.warn("failed to fetch connection token"
+						+ "for notification of completion check", e);
+			}
+		return toNotify;
+	}
+
+	@PerfLogged
+	@WithinSingleTransaction
+	public void markFinished(@Nonnull Set<String> terminated) {
+		for (String id : terminated) {
+			RunConnection rc = getById(id);
+			if (rc == null)
+				continue;
+			try {
+				rc.fromDBform(facade).doneTransitionToFinished = true;
+				rc.setFinished(true);
+			} catch (Exception e) {
+				log.warn("failed to note termination", e);
+			}
+		}
+	}
+}


[26/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
new file mode 100644
index 0000000..69705d9
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
@@ -0,0 +1,139 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.rest.ContentTypes.ATOM;
+
+import java.net.MalformedURLException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+
+/**
+ * A very stripped down ATOM feed for the interaction service.
+ * 
+ * @author Donal Fellows
+ */
+public interface InteractionFeedREST {
+	/**
+	 * Get the feed document for this ATOM feed.
+	 * 
+	 * @return The feed.
+	 * @throws FilesystemAccessException
+	 *             If we can't read from the feed directory.
+	 * @throws NoDirectoryEntryException
+	 *             If something changes things under our feet.
+	 */
+	@GET
+	@Path("/")
+	@Produces(ATOM)
+	@Description("Get the feed document for this ATOM feed.")
+	Feed getFeed() throws FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Adds an entry to this ATOM feed.
+	 * 
+	 * @param entry
+	 *            The entry to create.
+	 * @return A redirect to the created entry.
+	 * @throws MalformedURLException
+	 *             If we have problems generating the URI of the entry.
+	 * @throws FilesystemAccessException
+	 *             If we can't create the feed entry file.
+	 * @throws NoDirectoryEntryException
+	 *             If things get changed under our feet.
+	 * @throws NoUpdateException
+	 *             If we don't have permission to change things relating to this
+	 *             run.
+	 */
+	@POST
+	@Path("/")
+	@Consumes(ATOM)
+	@Produces(ATOM)
+	@Description("Adds an entry to this ATOM feed.")
+	Response addEntry(Entry entry) throws MalformedURLException,
+			FilesystemAccessException, NoDirectoryEntryException,
+			NoUpdateException;
+
+	/** Handles the OPTIONS request. */
+	@OPTIONS
+	@Path("/")
+	@Description("Describes what HTTP operations are supported on the feed.")
+	Response feedOptions();
+
+	/**
+	 * Gets the content of an entry in this ATOM feed.
+	 * 
+	 * @param id
+	 *            The ID of the entry to fetch.
+	 * @return The entry contents.
+	 * @throws FilesystemAccessException
+	 *             If we have problems reading the entry.
+	 * @throws NoDirectoryEntryException
+	 *             If we can't find the entry to read.
+	 */
+	@GET
+	@Path("{id}")
+	@Produces(ATOM)
+	@Description("Get the entry with a particular ID within this ATOM feed.")
+	Entry getEntry(@PathParam("id") String id)
+			throws FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Delete an entry from this ATOM feed.
+	 * 
+	 * @param id
+	 *            The ID of the entry to delete.
+	 * @return A simple message. Not very important!
+	 * @throws FilesystemAccessException
+	 *             If we have problems deleting the entry.
+	 * @throws NoDirectoryEntryException
+	 *             If we can't find the entry to delete.
+	 * @throws NoUpdateException
+	 *             If we don't have permission to alter things relating to this
+	 *             run.
+	 */
+	@DELETE
+	@Path("{id}")
+	@Produces("text/plain")
+	@Description("Deletes an entry from this ATOM feed.")
+	String deleteEntry(@PathParam("id") String id)
+			throws FilesystemAccessException, NoDirectoryEntryException,
+			NoUpdateException;
+
+	/** Handles the OPTIONS request. */
+	@OPTIONS
+	@Path("{id}")
+	@Description("Describes what HTTP operations are supported on an entry.")
+	Response entryOptions(@PathParam("{id}") String id);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
new file mode 100644
index 0000000..f877d7a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
@@ -0,0 +1,45 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+/**
+ * Description of what sort of event listener to create and attach to a workflow
+ * run. Bound via JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement(name = "listenerDefinition")
+@XmlType(name="ListenerDefinition")
+public class ListenerDefinition {
+	/**
+	 * The type of event listener to create.
+	 */
+	@XmlAttribute
+	public String type;
+	/**
+	 * How the event listener should be configured.
+	 */
+	@XmlValue
+	public String configuration;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
new file mode 100644
index 0000000..52e6d04
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
@@ -0,0 +1,69 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+/**
+ * The input to the REST interface for making directories and files, and
+ * uploading file contents. Done with JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement(name = "filesystemOperation")
+@XmlType(name = "FilesystemCreationOperation")
+@XmlSeeAlso( { MakeOrUpdateDirEntry.MakeDirectory.class,
+		MakeOrUpdateDirEntry.SetFileContents.class })
+public abstract class MakeOrUpdateDirEntry {
+	/**
+	 * The name of the file or directory that the operation applies to.
+	 */
+	@XmlAttribute
+	public String name;
+	/**
+	 * The contents of the file to upload.
+	 */
+	@XmlValue
+	public byte[] contents;
+
+	/**
+	 * Create a directory, described with JAXB. Should leave the
+	 * {@link MakeOrUpdateDirEntry#contents contents} field empty.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "mkdir")
+	@XmlType(name = "MakeDirectory")
+	public static class MakeDirectory extends MakeOrUpdateDirEntry {
+	}
+
+	/**
+	 * Create a file or set its contents, described with JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "upload")
+	@XmlType(name = "UploadFile")
+	public static class SetFileContents extends MakeOrUpdateDirEntry {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
new file mode 100644
index 0000000..1ed8a64
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
@@ -0,0 +1,253 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static java.util.Collections.unmodifiableList;
+import static javax.ws.rs.core.MediaType.WILDCARD;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.rest.ContentTypes.BYTES;
+import static org.taverna.server.master.rest.ContentTypes.JSON;
+import static org.taverna.server.master.rest.ContentTypes.URI_LIST;
+import static org.taverna.server.master.rest.ContentTypes.XML;
+import static org.taverna.server.master.rest.ContentTypes.ZIP;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.PathSegment;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.Variant;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * Representation of how a workflow run's working directory tree looks.
+ * 
+ * @author Donal Fellows
+ */
+@RolesAllowed(USER)
+@Produces({ XML, JSON })
+@Consumes({ XML, JSON })
+@Description("Representation of how a workflow run's working directory tree looks.")
+public interface TavernaServerDirectoryREST {
+	/**
+	 * Get the working directory of the workflow run.
+	 * 
+	 * @param ui
+	 *            About how this method was called.
+	 * @return A description of the working directory.
+	 * @throws FilesystemAccessException
+	 */
+	@GET
+	@Path("/")
+	@Description("Describes the working directory of the workflow run.")
+	@Nonnull
+	DirectoryContents getDescription(@Nonnull @Context UriInfo ui)
+			throws FilesystemAccessException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path("{path:.*}")
+	@Description("Produces the description of the files/directories' baclava operations.")
+	Response options(@PathParam("path") List<PathSegment> path);
+
+	/**
+	 * Gets a description of the named entity in or beneath the working
+	 * directory of the workflow run, which may be either a {@link Directory} or
+	 * a {@link File}.
+	 * 
+	 * @param path
+	 *            The path to the thing to describe.
+	 * @param ui
+	 *            About how this method was called.
+	 * @param headers
+	 *            About what the caller was looking for.
+	 * @return An HTTP response containing a description of the named thing.
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the file or directory can't be looked up.
+	 * @throws FilesystemAccessException
+	 *             If something went wrong during the filesystem operation.
+	 * @throws NegotiationFailedException
+	 *             If the content type being downloaded isn't one that this
+	 *             method can support.
+	 */
+	@GET
+	@Path("{path:.+}")
+	@Produces({ XML, JSON, BYTES, ZIP, WILDCARD })
+	@Description("Gives a description of the named entity in or beneath the "
+			+ "working directory of the workflow run (either a Directory or File).")
+	@Nonnull
+	Response getDirectoryOrFileContents(
+			@Nonnull @PathParam("path") List<PathSegment> path,
+			@Nonnull @Context UriInfo ui, @Nonnull @Context HttpHeaders headers)
+			throws NoDirectoryEntryException, FilesystemAccessException,
+			NegotiationFailedException;
+
+	/**
+	 * Creates a directory in the filesystem beneath the working directory of
+	 * the workflow run, or creates or updates a file's contents, where that
+	 * file is in or below the working directory of a workflow run.
+	 * 
+	 * @param parent
+	 *            The directory to create the directory in.
+	 * @param operation
+	 *            What to call the directory to create.
+	 * @param ui
+	 *            About how this method was called.
+	 * @return An HTTP response indicating where the directory was actually made
+	 *         or what file was created/updated.
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the containing directory can't be looked up.
+	 * @throws NoUpdateException
+	 *             If the user is not permitted to update the run.
+	 * @throws FilesystemAccessException
+	 *             If something went wrong during the filesystem operation.
+	 */
+	@POST
+	@Path("{path:.*}")
+	@Description("Creates a directory in the filesystem beneath the working "
+			+ "directory of the workflow run, or creates or updates a file's "
+			+ "contents, where that file is in or below the working directory "
+			+ "of a workflow run.")
+	@Nonnull
+	Response makeDirectoryOrUpdateFile(
+			@Nonnull @PathParam("path") List<PathSegment> parent,
+			@Nonnull MakeOrUpdateDirEntry operation,
+			@Nonnull @Context UriInfo ui) throws NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Creates or updates a file in a particular location beneath the working
+	 * directory of the workflow run.
+	 * 
+	 * @param file
+	 *            The path to the file to create or update.
+	 * @param referenceList
+	 *            Location to get the file's contents from. Must be
+	 *            <i>publicly</i> readable.
+	 * @param ui
+	 *            About how this method was called.
+	 * @return An HTTP response indicating what file was created/updated.
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the containing directory can't be looked up.
+	 * @throws NoUpdateException
+	 *             If the user is not permitted to update the run.
+	 * @throws FilesystemAccessException
+	 *             If something went wrong during the filesystem operation.
+	 */
+	@POST
+	@Path("{path:(.*)}")
+	@Consumes(URI_LIST)
+	@Description("Creates or updates a file in a particular location beneath the "
+			+ "working directory of the workflow run with the contents of a "
+			+ "publicly readable URL.")
+	@Nonnull
+	Response setFileContentsFromURL(@PathParam("path") List<PathSegment> file,
+			List<URI> referenceList, @Context UriInfo ui)
+			throws NoDirectoryEntryException, NoUpdateException,
+			FilesystemAccessException;
+
+    /**
+	 * Creates or updates a file in a particular location beneath the working
+	 * directory of the workflow run.
+	 * 
+	 * @param file
+	 *            The path to the file to create or update.
+	 * @param contents
+	 *            Stream of bytes to set the file's contents to.
+	 * @param ui
+	 *            About how this method was called.
+	 * @return An HTTP response indicating what file was created/updated.
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the containing directory can't be looked up.
+	 * @throws NoUpdateException
+	 *             If the user is not permitted to update the run.
+	 * @throws FilesystemAccessException
+	 *             If something went wrong during the filesystem operation.
+	 */
+	@PUT
+	@Path("{path:(.*)}")
+	@Consumes({ BYTES, WILDCARD })
+	@Description("Creates or updates a file in a particular location beneath the "
+			+ "working directory of the workflow run.")
+	@Nonnull
+	Response setFileContents(@PathParam("path") List<PathSegment> file,
+			InputStream contents, @Context UriInfo ui)
+			throws NoDirectoryEntryException, NoUpdateException,
+			FilesystemAccessException;
+
+	/**
+	 * Deletes a file or directory that is in or below the working directory of
+	 * a workflow run.
+	 * 
+	 * @param path
+	 *            The path to the file or directory.
+	 * @return An HTTP response to the method.
+	 * @throws NoUpdateException
+	 *             If the user is not permitted to update the run.
+	 * @throws FilesystemAccessException
+	 *             If something went wrong during the filesystem operation.
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the file or directory can't be looked up.
+	 */
+	@DELETE
+	@Path("{path:.*}")
+	@Description("Deletes a file or directory that is in or below the working "
+			+ "directory of a workflow run.")
+	@Nonnull
+	Response destroyDirectoryEntry(@PathParam("path") List<PathSegment> path)
+			throws NoUpdateException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Exception thrown to indicate a failure by the client to provide an
+	 * acceptable content type.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@SuppressWarnings("serial")
+	public static class NegotiationFailedException extends Exception {
+		public List<Variant> accepted;
+
+		public NegotiationFailedException(String msg, List<Variant> accepted) {
+			super(msg);
+			this.accepted = unmodifiableList(accepted);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerInputREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerInputREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerInputREST.java
new file mode 100644
index 0000000..154a1eb
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerInputREST.java
@@ -0,0 +1,368 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.rest.ContentTypes.JSON;
+import static org.taverna.server.master.rest.ContentTypes.TEXT;
+import static org.taverna.server.master.rest.ContentTypes.XML;
+import static org.taverna.server.master.rest.TavernaServerInputREST.PathNames.BACLAVA;
+import static org.taverna.server.master.rest.TavernaServerInputREST.PathNames.EXPECTED;
+import static org.taverna.server.master.rest.TavernaServerInputREST.PathNames.ONE_INPUT;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.PathSegment;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.taverna.server.master.common.Uri;
+import org.taverna.server.master.common.VersionedElement;
+import org.taverna.server.master.exceptions.BadInputPortNameException;
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Input;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.port_description.InputDescription;
+
+/**
+ * This represents how a Taverna Server workflow run's inputs looks to a RESTful
+ * API.
+ * 
+ * @author Donal Fellows.
+ */
+@RolesAllowed(USER)
+@Description("This represents how a Taverna Server workflow run's inputs "
+		+ "looks to a RESTful API.")
+public interface TavernaServerInputREST {
+	/**
+	 * @return A description of the various URIs to inputs associated with a
+	 *         workflow run.
+	 */
+	@GET
+	@Path("/")
+	@Produces({ XML, JSON })
+	@Description("Describe the sub-URIs of this resource.")
+	@Nonnull
+	InputsDescriptor get();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path("/")
+	@Description("Produces the description of one run's inputs' operations.")
+	Response options();
+
+	/**
+	 * @return A description of the various URIs to inputs associated with a
+	 *         workflow run.
+	 */
+	@GET
+	@Path(EXPECTED)
+	@Produces({ XML, JSON })
+	@Description("Describe the expected inputs of this workflow run.")
+	@Nonnull
+	InputDescription getExpected();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(EXPECTED)
+	@Description("Produces the description of the expected inputs' operations.")
+	Response expectedOptions();
+
+	/**
+	 * @return The Baclava file that will supply all the inputs to the workflow
+	 *         run, or empty to indicate that no such file is specified.
+	 */
+	@GET
+	@Path(BACLAVA)
+	@Produces(TEXT)
+	@Description("Gives the Baclava file describing the inputs, or empty if "
+			+ "individual files are used.")
+	@Nonnull
+	String getBaclavaFile();
+
+	/**
+	 * Set the Baclava file that will supply all the inputs to the workflow run.
+	 * 
+	 * @param filename
+	 *            The filename to set.
+	 * @return The name of the Baclava file that was actually set.
+	 * @throws NoUpdateException
+	 *             If the user can't update the run.
+	 * @throws BadStateChangeException
+	 *             If the run is not Initialized.
+	 * @throws FilesystemAccessException
+	 *             If the filename starts with a <tt>/</tt> or if it contains a
+	 *             <tt>..</tt> segment.
+	 */
+	@PUT
+	@Path(BACLAVA)
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Description("Sets the Baclava file describing the inputs.")
+	@Nonnull
+	String setBaclavaFile(@Nonnull String filename) throws NoUpdateException,
+			BadStateChangeException, FilesystemAccessException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(BACLAVA)
+	@Description("Produces the description of the inputs' baclava operations.")
+	Response baclavaOptions();
+
+	/**
+	 * Get what input is set for the specific input.
+	 * 
+	 * @param name
+	 *            The input to set.
+	 * @param uriInfo
+	 *            About the URI used to access this resource.
+	 * @return A description of the input.
+	 * @throws BadInputPortNameException
+	 *             If no input with that name exists.
+	 */
+	@GET
+	@Path(ONE_INPUT)
+	@Produces({ XML, JSON })
+	@Description("Gives a description of what is used to supply a particular "
+			+ "input.")
+	@Nonnull
+	InDesc getInput(@Nonnull @PathParam("name") String name,
+			@Context UriInfo uriInfo) throws BadInputPortNameException;
+
+	/**
+	 * Set what an input uses to provide data into the workflow run.
+	 * 
+	 * @param name
+	 *            The name of the input.
+	 * @param inputDescriptor
+	 *            A description of the input
+	 * @param uriInfo
+	 *            About the URI used to access this resource.
+	 * @return A description of the input.
+	 * @throws NoUpdateException
+	 *             If the user can't update the run.
+	 * @throws BadStateChangeException
+	 *             If the run is not Initialized.
+	 * @throws FilesystemAccessException
+	 *             If a filename is being set and the filename starts with a
+	 *             <tt>/</tt> or if it contains a <tt>..</tt> segment.
+	 * @throws BadInputPortNameException
+	 *             If no input with that name exists.
+	 * @throws BadPropertyValueException
+	 *             If some bad misconfiguration has happened.
+	 */
+	@PUT
+	@Path(ONE_INPUT)
+	@Consumes({ XML, JSON })
+	@Produces({ XML, JSON })
+	@Description("Sets the source for a particular input port.")
+	@Nonnull
+	InDesc setInput(@Nonnull @PathParam("name") String name,
+			@Nonnull InDesc inputDescriptor, @Context UriInfo uriInfo) throws NoUpdateException,
+			BadStateChangeException, FilesystemAccessException,
+			BadPropertyValueException, BadInputPortNameException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ONE_INPUT)
+	@Description("Produces the description of the one input's operations.")
+	Response inputOptions(@PathParam("name") String name);
+
+	interface PathNames {
+		final String EXPECTED = "expected";
+		final String BACLAVA = "baclava";
+		final String ONE_INPUT = "input/{name}";
+	}
+
+	/**
+	 * A description of the structure of inputs to a Taverna workflow run, done
+	 * with JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "runInputs")
+	@XmlType(name = "TavernaRunInputs")
+	public static class InputsDescriptor extends VersionedElement {
+		/**
+		 * Where to find a description of the expected inputs to this workflow
+		 * run.
+		 */
+		public Uri expected;
+		/**
+		 * Where to find the overall Baclava document filename (if set).
+		 */
+		public Uri baclava;
+		/**
+		 * Where to find the details of inputs to particular ports (if set).
+		 */
+		public List<Uri> input;
+
+		/**
+		 * Make a blank description of the inputs.
+		 */
+		public InputsDescriptor() {
+		}
+
+		/**
+		 * Make the description of the inputs.
+		 * 
+		 * @param ui
+		 *            Information about the URIs to generate.
+		 * @param run
+		 *            The run whose inputs are to be described.
+		 */
+		public InputsDescriptor(UriInfo ui, TavernaRun run) {
+			super(true);
+			expected = new Uri(ui, EXPECTED);
+			baclava = new Uri(ui, BACLAVA);
+			input = new ArrayList<>();
+			for (Input i : run.getInputs())
+				input.add(new Uri(ui, ONE_INPUT, i.getName()));
+		}
+	}
+
+	/**
+	 * The Details of a particular input port's value assignment, done with
+	 * JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "runInput")
+	@XmlType(name = "InputDescription")
+	public static class InDesc extends VersionedElement {
+		/** Make a blank description of an input port. */
+		public InDesc() {
+		}
+
+		/**
+		 * Make a description of the given input port.
+		 * 
+		 * @param inputPort
+		 */
+		public InDesc(Input inputPort, UriInfo ui) {
+			super(true);
+			name = inputPort.getName();
+			if (inputPort.getFile() != null) {
+				assignment = new InDesc.File();
+				assignment.contents = inputPort.getFile();
+			} else {
+				assignment = new InDesc.Value();
+				assignment.contents = inputPort.getValue();
+			}
+			// .../runs/{id}/input/input/{name} ->
+			// .../runs/{id}/input/expected#{name}
+			UriBuilder ub = ui.getBaseUriBuilder();
+			List<PathSegment> segments = ui.getPathSegments();
+			for (PathSegment s : segments.subList(0, segments.size() - 2))
+				ub.segment(s.getPath());
+			ub.fragment(name);
+			descriptorRef = new Uri(ub).ref;
+		}
+
+		/** The name of the port. */
+		@XmlAttribute(required = false)
+		public String name;
+		/** Where the port is described. Ignored in user input. */
+		@XmlAttribute(required = false)
+		@XmlSchemaType(name = "anyURI")
+		public URI descriptorRef;
+		/** The character to use to split the input into a list. */
+		@XmlAttribute(name = "listDelimiter", required = false)
+		public String delimiter;
+
+		/**
+		 * Either a filename or a literal string, used to provide input to a
+		 * workflow port.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "InputContents")
+		public static abstract class AbstractContents {
+			/**
+			 * The contents of the description of the input port. Meaning not
+			 * defined.
+			 */
+			@XmlValue
+			public String contents;
+		};
+
+		/**
+		 * The name of a file that provides input to the port. The
+		 * {@link AbstractContents#contents contents} field is a filename.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "")
+		public static class File extends AbstractContents {
+		}
+
+		/**
+		 * The literal input to the port. The {@link AbstractContents#contents
+		 * contents} field is a literal input value.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "")
+		public static class Value extends AbstractContents {
+		}
+
+		/**
+		 * A reference to a file elsewhere <i>on this server</i>. The
+		 * {@link AbstractContents#contents contents} field is a URL to the file
+		 * (using the RESTful notation).
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "")
+		public static class Reference extends AbstractContents {
+		}
+
+		/**
+		 * The assignment of input values to the port.
+		 */
+		@XmlElements({ @XmlElement(name = "file", type = File.class),
+				@XmlElement(name = "reference", type = Reference.class),
+				@XmlElement(name = "value", type = Value.class) })
+		public AbstractContents assignment;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerListenersREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerListenersREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerListenersREST.java
new file mode 100644
index 0000000..e554997
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerListenersREST.java
@@ -0,0 +1,441 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.rest.ContentTypes.JSON;
+import static org.taverna.server.master.rest.ContentTypes.TEXT;
+import static org.taverna.server.master.rest.ContentTypes.XML;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.taverna.server.master.common.Uri;
+import org.taverna.server.master.common.VersionedElement;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Listener;
+
+/**
+ * This represents <i>all</i> the event listeners attached to a workflow run.
+ * 
+ * @author Donal Fellows
+ * @see TavernaServerListenerREST
+ */
+@RolesAllowed(USER)
+@Description("This represents all the event listeners attached to a workflow "
+		+ "run.")
+public interface TavernaServerListenersREST {
+	/**
+	 * Get the listeners installed in the workflow run.
+	 * 
+	 * @param ui
+	 *            About how this method was called.
+	 * @return A list of descriptions of listeners.
+	 */
+	@GET
+	@Path("/")
+	@Produces({ XML, JSON })
+	@Description("Get the listeners installed in the workflow run.")
+	@Nonnull
+	Listeners getDescription(@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Add a new event listener to the named workflow run.
+	 * 
+	 * @param typeAndConfiguration
+	 *            What type of run should be created, and how should it be
+	 *            configured.
+	 * @param ui
+	 *            About how this method was called.
+	 * @return An HTTP response to the creation request.
+	 * @throws NoUpdateException
+	 *             If the user is not permitted to update the run.
+	 * @throws NoListenerException
+	 *             If no listener with the given type exists, or if the
+	 *             configuration is unacceptable in some way.
+	 */
+	@POST
+	@Path("/")
+	@Consumes({ XML, JSON })
+	@Description("Add a new event listener to the named workflow run.")
+	@Nonnull
+	Response addListener(@Nonnull ListenerDefinition typeAndConfiguration,
+			@Nonnull @Context UriInfo ui) throws NoUpdateException,
+			NoListenerException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path("/")
+	@Description("Produces the description of the run listeners' operations.")
+	Response listenersOptions();
+
+	/**
+	 * Resolve a particular listener from its name.
+	 * 
+	 * @param name
+	 *            The name of the listener to look up.
+	 * @return The listener's delegate in the REST world.
+	 * @throws NoListenerException
+	 *             If no listener with the given name exists.
+	 */
+	@Path("{name}")
+	@Description("Resolve a particular listener from its name.")
+	@Nonnull
+	TavernaServerListenerREST getListener(
+			@Nonnull @PathParam("name") String name) throws NoListenerException;
+
+	/**
+	 * This represents a single event listener attached to a workflow run.
+	 * 
+	 * @author Donal Fellows
+	 * @see TavernaServerListenersREST
+	 * @see Property
+	 */
+	@RolesAllowed(USER)
+	@Description("This represents a single event listener attached to a "
+			+ "workflow run.")
+	public interface TavernaServerListenerREST {
+		/**
+		 * Get the description of this listener.
+		 * 
+		 * @param ui
+		 *            Information about this request.
+		 * @return A description document.
+		 */
+		@GET
+		@Path("/")
+		@Produces({ XML, JSON })
+		@Description("Get the description of this listener.")
+		@Nonnull
+		ListenerDescription getDescription(@Nonnull @Context UriInfo ui);
+
+		/** Get an outline of the operations supported. */
+		@OPTIONS
+		@Path("/")
+		@Description("Produces the description of one run listener's operations.")
+		Response listenerOptions();
+
+		/**
+		 * Get the configuration for the given event listener that is attached
+		 * to a workflow run.
+		 * 
+		 * @return The configuration of the listener.
+		 */
+		@GET
+		@Path("configuration")
+		@Produces(TEXT)
+		@Description("Get the configuration for the given event listener that "
+				+ "is attached to a workflow run.")
+		@Nonnull
+		String getConfiguration();
+
+		/** Get an outline of the operations supported. */
+		@OPTIONS
+		@Path("configuration")
+		@Description("Produces the description of one run listener's "
+				+ "configuration's operations.")
+		Response configurationOptions();
+
+		/**
+		 * Get the list of properties supported by a given event listener
+		 * attached to a workflow run.
+		 * 
+		 * @param ui
+		 *            Information about this request.
+		 * @return The list of property names.
+		 */
+		@GET
+		@Path("properties")
+		@Produces({ XML, JSON })
+		@Description("Get the list of properties supported by a given event "
+				+ "listener attached to a workflow run.")
+		@Nonnull
+		Properties getProperties(@Nonnull @Context UriInfo ui);
+
+		/** Get an outline of the operations supported. */
+		@OPTIONS
+		@Path("properties")
+		@Description("Produces the description of one run listener's "
+				+ "properties' operations.")
+		Response propertiesOptions();
+
+		/**
+		 * Get an object representing a particular property.
+		 * 
+		 * @param propertyName
+		 * @return The property delegate.
+		 * @throws NoListenerException
+		 *             If there is no such property.
+		 */
+		@Path("properties/{propertyName}")
+		@Description("Get an object representing a particular property.")
+		@Nonnull
+		Property getProperty(
+				@Nonnull @PathParam("propertyName") String propertyName)
+				throws NoListenerException;
+	}
+
+	/**
+	 * This represents a single property attached of an event listener.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@RolesAllowed(USER)
+	@Description("This represents a single property attached of an event "
+			+ "listener.")
+	public interface Property {
+		/**
+		 * Get the value of the particular property of an event listener
+		 * attached to a workflow run.
+		 * 
+		 * @return The value of the property.
+		 */
+		@GET
+		@Path("/")
+		@Produces(TEXT)
+		@Description("Get the value of the particular property of an event "
+				+ "listener attached to a workflow run.")
+		@Nonnull
+		String getValue();
+
+		/**
+		 * Set the value of the particular property of an event listener
+		 * attached to a workflow run. Changing the value of the property may
+		 * cause the listener to alter its behaviour significantly.
+		 * 
+		 * @param value
+		 *            The value to set the property to.
+		 * @return The value of the property after being set.
+		 * @throws NoUpdateException
+		 *             If the user is not permitted to update the run.
+		 * @throws NoListenerException
+		 *             If the property is in the wrong format.
+		 */
+		@PUT
+		@Path("/")
+		@Consumes(TEXT)
+		@Produces(TEXT)
+		@Description("Set the value of the particular property of an event "
+				+ "listener attached to a workflow run.")
+		@Nonnull
+		String setValue(@Nonnull String value) throws NoUpdateException,
+				NoListenerException;
+
+		/** Get an outline of the operations supported. */
+		@OPTIONS
+		@Path("/")
+		@Description("Produces the description of one run listener's "
+				+ "property's operations.")
+		Response options();
+	}
+
+	/**
+	 * A description of an event listener that is attached to a workflow run.
+	 * Done with JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "ListenerDescription")
+	public class ListenerDescription extends VersionedElement {
+		/** Where this listener is located. */
+		@XmlAttribute(name = "href", namespace = XLINK)
+		@XmlSchemaType(name = "anyURI")
+		public URI location;
+		/** The (arbitrary) name of the event listener. */
+		@XmlAttribute
+		public String name;
+		/** The type of the event listener. */
+		@XmlAttribute
+		public String type;
+		/**
+		 * The location of the configuration document for the event listener.
+		 */
+		public Uri configuration;
+		/**
+		 * The name and location of the properties supported by the event
+		 * listener.
+		 */
+		@XmlElementWrapper(name = "properties", nillable = false)
+		@XmlElement(name = "property", nillable = false)
+		public List<PropertyDescription> properties;
+
+		/**
+		 * Make a blank listener description.
+		 */
+		public ListenerDescription() {
+		}
+
+		/**
+		 * Make a listener description that characterizes the given listener.
+		 * 
+		 * @param listener
+		 *            The listener to describe.
+		 * @param ub
+		 *            The factory for URIs. Must have already been secured.
+		 */
+		public ListenerDescription(Listener listener, UriBuilder ub) {
+			super(true);
+			name = listener.getName();
+			type = listener.getType();
+			configuration = new Uri(ub.clone().path("configuration"));
+			UriBuilder ub2 = ub.clone().path("properties/{prop}");
+			String[] props = listener.listProperties();
+			properties = new ArrayList<>(props.length);
+			for (String propName : props)
+				properties.add(new PropertyDescription(propName, ub2));
+		}
+	}
+
+	/**
+	 * The description of a single property, done with JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlType(name = "PropertyDescription")
+	public static class PropertyDescription extends Uri {
+		/**
+		 * The name of the property.
+		 */
+		@XmlAttribute
+		String name;
+
+		/**
+		 * Make an empty description of a property.
+		 */
+		public PropertyDescription() {
+		}
+
+		/**
+		 * Make a description of a property.
+		 * 
+		 * @param listenerName
+		 *            The name of the listener whose property this is.
+		 * @param propName
+		 *            The name of the property.
+		 * @param ub
+		 *            The factory for URIs. Must have already been secured.
+		 */
+		PropertyDescription(String propName, UriBuilder ub) {
+			super(ub, propName);
+			this.name = propName;
+		}
+	}
+
+	/**
+	 * The list of descriptions of listeners attached to a run. Done with JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "")
+	public static class Listeners extends VersionedElement {
+		/**
+		 * The listeners for a workflow run.
+		 */
+		@XmlElement(name = "listener")
+		public List<ListenerDescription> listener;
+
+		/**
+		 * Make a blank description of listeners.
+		 */
+		public Listeners() {
+			listener = new ArrayList<>();
+		}
+
+		/**
+		 * Make a description of the whole group out of the given list of
+		 * listener descriptions.
+		 * 
+		 * @param listeners
+		 *            The collection of (partial) listener descriptions.
+		 * @param ub
+		 *            How to build the location of the listeners. Must have
+		 *            already been secured.
+		 */
+		public Listeners(List<ListenerDescription> listeners, UriBuilder ub) {
+			super(true);
+			listener = listeners;
+			for (ListenerDescription ld : listeners)
+				ld.location = ub.build(ld.name);
+		}
+	}
+
+	/**
+	 * The list of properties of a listener. Done with JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "")
+	public static class Properties extends VersionedElement {
+		/**
+		 * The references to the properties of a listener.
+		 */
+		@XmlElement
+		public List<PropertyDescription> property;
+
+		/**
+		 * Make an empty description of the properties of a listener.
+		 */
+		public Properties() {
+		}
+
+		/**
+		 * Make the description of the properties of a listener.
+		 * 
+		 * @param ub
+		 *            The factory for URIs, configured. Must have already been
+		 *            secured.
+		 * @param properties
+		 *            The names of the properties.
+		 */
+		public Properties(UriBuilder ub, String[] properties) {
+			super(true);
+			property = new ArrayList<>(properties.length);
+			for (String propName : properties)
+				property.add(new PropertyDescription(propName, ub));
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerREST.java
new file mode 100644
index 0000000..161b017
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerREST.java
@@ -0,0 +1,617 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.rest.ContentTypes.JSON;
+import static org.taverna.server.master.rest.ContentTypes.URI_LIST;
+import static org.taverna.server.master.rest.ContentTypes.XML;
+import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL;
+import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_CAPABILITIES;
+import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_NOTIFIERS;
+import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_OP_LIMIT;
+import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_PERM_LIST;
+import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_PERM_WF;
+import static org.taverna.server.master.rest.TavernaServerREST.PathNames.POL_RUN_LIMIT;
+import static org.taverna.server.master.rest.TavernaServerREST.PathNames.ROOT;
+import static org.taverna.server.master.rest.TavernaServerREST.PathNames.RUNS;
+import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.taverna.server.master.common.Capability;
+import org.taverna.server.master.common.RunReference;
+import org.taverna.server.master.common.Uri;
+import org.taverna.server.master.common.VersionedElement;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.common.version.Version;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.soap.TavernaServerSOAP;
+
+/**
+ * The REST service interface to Taverna 3 Server.
+ * 
+ * @author Donal Fellows
+ * @see TavernaServerSOAP
+ */
+@RolesAllowed(USER)
+@Description("This is REST service interface to Taverna " + Version.JAVA
+		+ " Server.")
+public interface TavernaServerREST {
+	/**
+	 * Produces the description of the service.
+	 * 
+	 * @param ui
+	 *            About the URI being accessed.
+	 * @return The description.
+	 */
+	@GET
+	@Path(ROOT)
+	@Produces({ XML, JSON })
+	@Description("Produces the description of the service.")
+	@Nonnull
+	ServerDescription describeService(@Nonnull @Context UriInfo ui);
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ROOT)
+	@Description("Produces the description of the service.")
+	Response serviceOptions();
+
+	/**
+	 * Produces a description of the list of runs.
+	 * 
+	 * @param ui
+	 *            About the URI being accessed.
+	 * @return A description of the list of runs that are available.
+	 */
+	@GET
+	@Path(RUNS)
+	@Produces({ XML, JSON })
+	@RolesAllowed(USER)
+	@Description("Produces a list of all runs visible to the user.")
+	@Nonnull
+	RunList listUsersRuns(@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Accepts (or not) a request to create a new run executing the given
+	 * workflow.
+	 * 
+	 * @param workflow
+	 *            The workflow document to execute.
+	 * @param ui
+	 *            About the URI being accessed.
+	 * @return A response to the POST describing what was created.
+	 * @throws NoUpdateException
+	 *             If the POST failed.
+	 */
+	@POST
+	@Path(RUNS)
+	@Consumes({ T2FLOW, SCUFL2, XML })
+	@RolesAllowed(USER)
+	@Description("Accepts (or not) a request to create a new run executing "
+			+ "the given workflow.")
+	@Nonnull
+	Response submitWorkflow(@Nonnull Workflow workflow,
+			@Nonnull @Context UriInfo ui) throws NoUpdateException;
+
+	/**
+	 * Accepts (or not) a request to create a new run executing the workflow at
+	 * the given location.
+	 * 
+	 * @param workflowReference
+	 *            The wrapped URI to workflow document to execute.
+	 * @param ui
+	 *            About the URI being POSTed to.
+	 * @return A response to the POST describing what was created.
+	 * @throws NoUpdateException
+	 *             If the POST failed.
+	 * @throw NoCreateException If the workflow couldn't be read into the server
+	 *        or the engine rejects it.
+	 */
+	@POST
+	@Path(RUNS)
+	@Consumes(URI_LIST)
+	@RolesAllowed(USER)
+	@Description("Accepts a URL to a workflow to download and run. The URL "
+			+ "must be hosted on a publicly-accessible service.")
+	@Nonnull
+	Response submitWorkflowByURL(@Nonnull List<URI> referenceList,
+			@Nonnull @Context UriInfo ui) throws NoCreateException,
+			NoUpdateException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(RUNS)
+	@Description("Produces the description of the operations on the "
+			+ "collection of runs.")
+	Response runsOptions();
+
+	/**
+	 * @return A description of the policies supported by this server.
+	 */
+	@Path(POL)
+	@Description("The policies supported by this server.")
+	@Nonnull
+	PolicyView getPolicyDescription();
+
+	/**
+	 * Get a particular named run resource.
+	 * 
+	 * @param runName
+	 *            The name of the run.
+	 * @param uriInfo
+	 *            About the URI used to access this run.
+	 * @return A RESTful delegate for the run.
+	 * @throws UnknownRunException
+	 *             If the run handle is unknown to the current user.
+	 */
+	@Path(RUNS + "/{runName}")
+	@RolesAllowed(USER)
+	@Description("Get a particular named run resource to dispatch to.")
+	@Nonnull
+	TavernaServerRunREST getRunResource(
+			@Nonnull @PathParam("runName") String runName,
+			@Nonnull @Context UriInfo uriInfo) throws UnknownRunException;
+
+	/**
+	 * Factored out path names used in the {@link TavernaServerREST} interface
+	 * and related places.
+	 * 
+	 * @author Donal Fellows
+	 */
+	interface PathNames {
+		public static final String ROOT = "/";
+		public static final String RUNS = "runs";
+		public static final String POL = "policy";
+		public static final String POL_CAPABILITIES = "capabilities";
+		public static final String POL_RUN_LIMIT = "runLimit";
+		public static final String POL_OP_LIMIT = "operatingLimit";
+		public static final String POL_PERM_WF = "permittedWorkflows";
+		public static final String POL_PERM_LIST = "permittedListenerTypes";
+		public static final String POL_NOTIFIERS = "enabledNotificationFabrics";
+	}
+
+	/**
+	 * Helper class for describing the server's user-facing management API via
+	 * JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "")
+	public static class ServerDescription extends VersionedElement {
+		/**
+		 * References to the collection of runs (known about by the current
+		 * user) in this server.
+		 */
+		public Uri runs;
+		/**
+		 * Reference to the policy description part of this server.
+		 */
+		public Uri policy;
+		/**
+		 * Reference to the Atom event feed produced by this server.
+		 */
+		public Uri feed;
+		/**
+		 * Reference to the interaction feed for this server.
+		 */
+		public Uri interactionFeed;
+
+		/** Make a blank server description. */
+		public ServerDescription() {
+		}
+
+		/**
+		 * Make a description of the server.
+		 * 
+		 * @param ui
+		 *            The factory for URIs.
+		 */
+		public ServerDescription(UriInfo ui, String interactionFeed) {
+			super(true);
+			String base = ui.getBaseUri().toString();
+			runs = new Uri(ui, RUNS);
+			policy = new Uri(ui, false, POL);
+			feed = new Uri(java.net.URI.create(base.replaceFirst("/rest$",
+					"/feed")));
+			if (interactionFeed != null && !interactionFeed.isEmpty())
+				this.interactionFeed = new Uri(
+						java.net.URI.create(interactionFeed));
+		}
+	}
+
+	/**
+	 * How to discover the publicly-visible policies supported by this server.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public interface PolicyView {
+		/**
+		 * Describe the URIs in this view of the server's policies.
+		 * 
+		 * @param ui
+		 *            About the URI used to retrieve the description.
+		 * @return The description, which may be serialised as XML or JSON.
+		 */
+		@GET
+		@Path(ROOT)
+		@Produces({ XML, JSON })
+		@Description("Describe the parts of this policy.")
+		@Nonnull
+		public PolicyDescription getDescription(@Nonnull @Context UriInfo ui);
+
+		/**
+		 * Gets the maximum number of simultaneous runs that the user may
+		 * create. The <i>actual</i> number they can create may be lower than
+		 * this. If this number is lower than the number they currently have,
+		 * they will be unable to create any runs at all.
+		 * 
+		 * @return The maximum number of existing runs.
+		 */
+		@GET
+		@Path(POL_RUN_LIMIT)
+		@Produces("text/plain")
+		@RolesAllowed(USER)
+		@Description("Gets the maximum number of simultaneous runs in any "
+				+ "state that the user may create.")
+		@Nonnull
+		public int getMaxSimultaneousRuns();
+
+		/**
+		 * Gets the maximum number of simultaneous
+		 * {@linkplain org.taverna.server.master.common.Status.Operating
+		 * operating} runs that the user may create. The <i>actual</i> number
+		 * they can start may be lower than this. If this number is lower than
+		 * the number they currently have, they will be unable to start any runs
+		 * at all.
+		 * 
+		 * @return The maximum number of operating runs.
+		 */
+		@GET
+		@Path(POL_OP_LIMIT)
+		@Produces("text/plain")
+		@RolesAllowed(USER)
+		@Description("Gets the maximum number of simultaneously operating "
+				+ "runs that the user may have. Note that this is often a "
+				+ "global limit; it does not represent a promise that a "
+				+ "particular user may be able to have that many operating "
+				+ "runs at once.")
+		public int getMaxOperatingRuns();
+
+		/**
+		 * Gets the list of permitted workflows. Any workflow may be submitted
+		 * if the list is empty, otherwise it must be one of the workflows on
+		 * this list.
+		 * 
+		 * @return The list of workflow documents.
+		 */
+		@GET
+		@Path(POL_PERM_WF)
+		@Produces({ XML, JSON })
+		@RolesAllowed(USER)
+		@Description("Gets the list of permitted workflows.")
+		@Nonnull
+		public PermittedWorkflows getPermittedWorkflows();
+
+		/**
+		 * Gets the list of permitted event listener types. All event listeners
+		 * must be of a type described on this list.
+		 * 
+		 * @return The types of event listeners allowed.
+		 */
+		@GET
+		@Path(POL_PERM_LIST)
+		@Produces({ XML, JSON })
+		@RolesAllowed(USER)
+		@Description("Gets the list of permitted event listener types.")
+		@Nonnull
+		public PermittedListeners getPermittedListeners();
+
+		/**
+		 * Gets the list of supported, enabled notification fabrics. Each
+		 * corresponds (approximately) to a protocol, e.g., email.
+		 * 
+		 * @return List of notifier names; each is the scheme of a notification
+		 *         destination URI.
+		 */
+		@GET
+		@Path(POL_NOTIFIERS)
+		@Produces({ XML, JSON })
+		@RolesAllowed(USER)
+		@Description("Gets the list of supported, enabled notification "
+				+ "fabrics. Each corresponds (approximately) to a protocol, "
+				+ "e.g., email.")
+		@Nonnull
+		public EnabledNotificationFabrics getEnabledNotifiers();
+
+		@GET
+		@Path(POL_CAPABILITIES)
+		@Produces({ XML, JSON })
+		@RolesAllowed(USER)
+		@Description("Gets a description of the capabilities supported by "
+				+ "this installation of Taverna Server.")
+		@Nonnull
+		public CapabilityList getCapabilities();
+
+		/**
+		 * A description of the parts of a server policy.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlRootElement
+		@XmlType(name = "")
+		public static class PolicyDescription extends VersionedElement {
+			/**
+			 * Where to go to find out about the maximum number of runs.
+			 */
+			public Uri runLimit;
+			/**
+			 * Where to go to find out about the maximum number of operating
+			 * runs.
+			 */
+			public Uri operatingLimit;
+			/**
+			 * Where to go to find out about what workflows are allowed.
+			 */
+			public Uri permittedWorkflows;
+			/**
+			 * Where to go to find out about what listeners are allowed.
+			 */
+			public Uri permittedListenerTypes;
+			/**
+			 * How notifications may be sent.
+			 */
+			public Uri enabledNotificationFabrics;
+
+			public Uri capabilities;
+
+			/** Make a blank server description. */
+			public PolicyDescription() {
+			}
+
+			/**
+			 * Make a server description.
+			 * 
+			 * @param ui
+			 *            About the URI used to access this description.
+			 */
+			public PolicyDescription(UriInfo ui) {
+				super(true);
+				runLimit = new Uri(ui, false, POL_RUN_LIMIT);
+				operatingLimit = new Uri(ui, false, POL_OP_LIMIT);
+				permittedWorkflows = new Uri(ui, false, POL_PERM_WF);
+				permittedListenerTypes = new Uri(ui, false, POL_PERM_LIST);
+				enabledNotificationFabrics = new Uri(ui, false, POL_NOTIFIERS);
+				capabilities = new Uri(ui, false, POL_CAPABILITIES);
+			}
+		}
+
+		/**
+		 * A list of Taverna Server capabilities.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlRootElement(name = "capabilities")
+		@XmlType(name = "")
+		public static class CapabilityList {
+			@XmlElement(name = "capability", namespace = SERVER)
+			public List<Capability> capability = new ArrayList<>();
+		}
+	}
+
+	/**
+	 * Helper class for describing the workflows that are allowed via JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "")
+	public static class PermittedWorkflows {
+		/** The workflows that are permitted. */
+		@XmlElement
+		public List<URI> workflow;
+
+		/**
+		 * Make an empty list of permitted workflows.
+		 */
+		public PermittedWorkflows() {
+			workflow = new ArrayList<>();
+		}
+
+		/**
+		 * Make a list of permitted workflows.
+		 * 
+		 * @param permitted
+		 */
+		public PermittedWorkflows(List<URI> permitted) {
+			if (permitted == null)
+				workflow = new ArrayList<>();
+			else
+				workflow = new ArrayList<>(permitted);
+		}
+	}
+
+	/**
+	 * Helper class for describing the listener types that are allowed via JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "")
+	public static class PermittedListeners {
+		/** The listener types that are permitted. */
+		@XmlElement
+		public List<String> type;
+
+		/**
+		 * Make an empty list of permitted listener types.
+		 */
+		public PermittedListeners() {
+			type = new ArrayList<>();
+		}
+
+		/**
+		 * Make a list of permitted listener types.
+		 * 
+		 * @param listenerTypes
+		 */
+		public PermittedListeners(List<String> listenerTypes) {
+			type = listenerTypes;
+		}
+	}
+
+	/**
+	 * Helper class for describing the workflow runs.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "")
+	public static class RunList {
+		/** The references to the workflow runs. */
+		@XmlElement
+		public List<RunReference> run;
+
+		/**
+		 * Make an empty list of run references.
+		 */
+		public RunList() {
+			run = new ArrayList<>();
+		}
+
+		/**
+		 * Make a list of references to workflow runs.
+		 * 
+		 * @param runs
+		 *            The mapping of runs to describe.
+		 * @param ub
+		 *            How to construct URIs to the runs. Must have already been
+		 *            secured as it needs to have its pattern applied.
+		 */
+		public RunList(Map<String, TavernaRun> runs, UriBuilder ub) {
+			run = new ArrayList<>(runs.size());
+			for (String name : runs.keySet())
+				run.add(new RunReference(name, ub));
+		}
+	}
+
+	/**
+	 * Helper class for describing the listener types that are allowed via JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "")
+	public static class EnabledNotificationFabrics {
+		/** The notification fabrics that are enabled. */
+		@XmlElement
+		public List<String> notifier;
+
+		/**
+		 * Make an empty list of enabled notifiers.
+		 */
+		public EnabledNotificationFabrics() {
+			notifier = new ArrayList<>();
+		}
+
+		/**
+		 * Make a list of enabled notifiers.
+		 * 
+		 * @param enabledNodifiers
+		 */
+		public EnabledNotificationFabrics(List<String> enabledNodifiers) {
+			notifier = enabledNodifiers;
+		}
+	}
+
+	/**
+	 * The interface exposed by the Atom feed of events.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@RolesAllowed(USER)
+	public interface EventFeed {
+		/**
+		 * @return the feed of events for the current user.
+		 */
+		@GET
+		@Path("/")
+		@Produces("application/atom+xml;type=feed")
+		@Description("Get an Atom feed for the user's events.")
+		@Nonnull
+		Feed getFeed(@Context UriInfo ui);
+
+		/**
+		 * @param id
+		 *            The identifier for a particular event.
+		 * @return the details about the given event.
+		 */
+		@GET
+		@Path("{id}")
+		@Produces("application/atom+xml;type=entry")
+		@Description("Get a particular Atom event.")
+		@Nonnull
+		Entry getEvent(@Nonnull @PathParam("id") String id);
+	}
+
+	/**
+	 * A reference to a workflow hosted on some public HTTP server.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "workflowurl")
+	@XmlType(name = "WorkflowReference")
+	public static class WorkflowReference {
+		@XmlValue
+		@XmlSchemaType(name = "anyURI")
+		public URI url;
+	}
+}


[42/42] incubator-taverna-server git commit: package org.apache.taverna.server.*

Posted by st...@apache.org.
package org.apache.taverna.server.*


Project: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/commit/46777e2c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/tree/46777e2c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/diff/46777e2c

Branch: refs/heads/master
Commit: 46777e2c6624c382edfd65949ab515cafd1c7e37
Parents: 00397ef
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Tue Jan 9 23:23:09 2018 +0000
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Tue Jan 9 23:23:58 2018 +0000

----------------------------------------------------------------------
 pom.xml                                         |  36 ++---
 .../server/port_description/AbsentValue.java    |   2 +-
 .../server/port_description/AbstractPort.java   |   4 +-
 .../AbstractPortDescription.java                |   2 +-
 .../server/port_description/AbstractValue.java  |   4 +-
 .../server/port_description/ErrorValue.java     |   4 +-
 .../port_description/InputDescription.java      |   4 +-
 .../server/port_description/LeafValue.java      |   2 +-
 .../server/port_description/ListValue.java      |   4 +-
 .../server/port_description/Namespaces.java     |   2 +-
 .../port_description/OutputDescription.java     |   2 +-
 .../server/port_description/package-info.java   |   8 +-
 .../port_description/utils/IntAdapter.java      |   2 +-
 .../server/port_description/JaxbSanityTest.java |   2 +-
 taverna-server-rmidaemon/pom.xml                |   2 +-
 .../taverna/server/rmidaemon/Registry.java      |   2 +-
 .../taverna/server/rmidaemon/package-info.java  |   2 +-
 .../remote/IllegalStateTransitionException.java |   2 +-
 .../remote/ImplementationException.java         |   2 +-
 .../localworker/remote/RemoteDirectory.java     |   2 +-
 .../remote/RemoteDirectoryEntry.java            |   2 +-
 .../server/localworker/remote/RemoteFile.java   |   2 +-
 .../server/localworker/remote/RemoteInput.java  |   2 +-
 .../localworker/remote/RemoteListener.java      |   2 +-
 .../localworker/remote/RemoteRunFactory.java    |   4 +-
 .../remote/RemoteSecurityContext.java           |   2 +-
 .../localworker/remote/RemoteSingleRun.java     |   2 +-
 .../server/localworker/remote/RemoteStatus.java |   2 +-
 .../remote/StillWorkingOnItException.java       |   2 +-
 .../server/localworker/remote/package-info.java |   2 +-
 .../localworker/server/UsageRecordReceiver.java |   2 +-
 .../server/localworker/server/package-info.java |   2 +-
 taverna-server-unix-forker/pom.xml              |   2 +-
 .../taverna/server/unixforker/Forker.java       |   2 +-
 taverna-server-webapp/pom.xml                   |  12 +-
 .../master/ContentsDescriptorBuilder.java       |  40 +++---
 .../taverna/server/master/DirectoryREST.java    |  48 +++----
 .../server/master/FileConcatenation.java        |   6 +-
 .../apache/taverna/server/master/InputREST.java |  44 +++----
 .../taverna/server/master/InteractionFeed.java  |  26 ++--
 .../server/master/ListenerPropertyREST.java     |  20 +--
 .../taverna/server/master/ListenersREST.java    |  24 ++--
 .../taverna/server/master/ManagementState.java  |   6 +-
 .../apache/taverna/server/master/RunREST.java   |  56 ++++----
 .../taverna/server/master/RunSecurityREST.java  |  32 ++---
 .../server/master/SingleListenerREST.java       |  24 ++--
 .../taverna/server/master/TavernaServer.java    | 132 +++++++++----------
 .../server/master/TavernaServerSupport.java     |  70 +++++-----
 .../taverna/server/master/admin/Admin.java      |  74 +++++------
 .../taverna/server/master/admin/AdminBean.java  |  26 ++--
 .../server/master/admin/package-info.java       |  18 +--
 .../taverna/server/master/api/ContentTypes.java |   2 +-
 .../server/master/api/DirectoryBean.java        |   8 +-
 .../taverna/server/master/api/FeedBean.java     |   6 +-
 .../taverna/server/master/api/InputBean.java    |  12 +-
 .../server/master/api/ListenerPropertyBean.java |   8 +-
 .../server/master/api/ListenersBean.java        |   6 +-
 .../server/master/api/ManagementModel.java      |   2 +-
 .../server/master/api/OneListenerBean.java      |   8 +-
 .../taverna/server/master/api/RunBean.java      |   8 +-
 .../taverna/server/master/api/SecurityBean.java |   8 +-
 .../taverna/server/master/api/SupportAware.java |   4 +-
 .../server/master/api/TavernaServerBean.java    |  24 ++--
 .../taverna/server/master/api/package-info.java |   2 +-
 .../server/master/common/Capability.java        |   2 +-
 .../server/master/common/Credential.java        |   4 +-
 .../server/master/common/DirEntryReference.java |   8 +-
 .../server/master/common/InputDescription.java  |   6 +-
 .../server/master/common/Namespaces.java        |   2 +-
 .../server/master/common/Permission.java        |   4 +-
 .../server/master/common/ProfileList.java       |   2 +-
 .../taverna/server/master/common/Roles.java     |   2 +-
 .../server/master/common/RunReference.java      |  10 +-
 .../taverna/server/master/common/Status.java    |   2 +-
 .../taverna/server/master/common/Trust.java     |   4 +-
 .../taverna/server/master/common/Uri.java       |   4 +-
 .../server/master/common/VersionedElement.java  |   4 +-
 .../taverna/server/master/common/Workflow.java  |  14 +-
 .../server/master/common/package-info.java      |  14 +-
 .../server/master/common/version/Version.java   |   6 +-
 .../taverna/server/master/defaults/Default.java |   6 +-
 .../server/master/defaults/package-info.java    |   2 +-
 .../exceptions/BadInputPortNameException.java   |   2 +-
 .../exceptions/BadPropertyValueException.java   |   2 +-
 .../exceptions/BadStateChangeException.java     |   2 +-
 .../exceptions/FilesystemAccessException.java   |   2 +-
 .../exceptions/GeneralFailureException.java     |   4 +-
 .../exceptions/InvalidCredentialException.java  |   2 +-
 .../master/exceptions/NoCreateException.java    |   2 +-
 .../exceptions/NoCredentialException.java       |   2 +-
 .../master/exceptions/NoDestroyException.java   |   2 +-
 .../exceptions/NoDirectoryEntryException.java   |   2 +-
 .../master/exceptions/NoListenerException.java  |   2 +-
 .../master/exceptions/NoUpdateException.java    |   2 +-
 .../master/exceptions/NotOwnerException.java    |   2 +-
 .../master/exceptions/OverloadedException.java  |   2 +-
 .../master/exceptions/UnknownRunException.java  |   2 +-
 .../server/master/exceptions/package-info.java  |  14 +-
 .../taverna/server/master/facade/Facade.java    |   4 +-
 .../server/master/facade/package-info.java      |   2 +-
 .../factories/ConfigurableRunFactory.java       |   2 +-
 .../master/factories/ListenerFactory.java       |   8 +-
 .../server/master/factories/RunFactory.java     |  10 +-
 .../server/master/factories/package-info.java   |   2 +-
 .../identity/AuthorityDerivedIDMapper.java      |   8 +-
 .../master/identity/CompositeIDMapper.java      |   6 +-
 .../master/identity/ConstantIDMapper.java       |   6 +-
 .../server/master/identity/NameIDMapper.java    |   6 +-
 .../identity/StrippedDownAuthProvider.java      |   4 +-
 .../taverna/server/master/identity/User.java    |   8 +-
 .../server/master/identity/UserStore.java       |  14 +-
 .../server/master/identity/UserStoreAPI.java    |   2 +-
 .../identity/WorkflowInternalAuthProvider.java  |  16 +--
 .../server/master/identity/package-info.java    |   2 +-
 .../interaction/InteractionFeedSupport.java     |  22 ++--
 .../server/master/interaction/package-info.java |   2 +-
 .../server/master/interfaces/Directory.java     |   4 +-
 .../master/interfaces/DirectoryEntry.java       |   4 +-
 .../taverna/server/master/interfaces/File.java  |   4 +-
 .../taverna/server/master/interfaces/Input.java |   8 +-
 .../server/master/interfaces/Listener.java      |   6 +-
 .../master/interfaces/LocalIdentityMapper.java  |   4 +-
 .../master/interfaces/MessageDispatcher.java    |   2 +-
 .../server/master/interfaces/Policy.java        |  14 +-
 .../server/master/interfaces/RunStore.java      |   6 +-
 .../interfaces/SecurityContextFactory.java      |   4 +-
 .../server/master/interfaces/TavernaRun.java    |  14 +-
 .../interfaces/TavernaSecurityContext.java      |  12 +-
 .../master/interfaces/UriBuilderFactory.java    |   2 +-
 .../server/master/interfaces/package-info.java  |   2 +-
 .../localworker/AbstractRemoteRunFactory.java   |  44 +++----
 .../master/localworker/ForkRunFactory.java      |  16 +--
 .../localworker/IdAwareForkRunFactory.java      |  20 +--
 .../master/localworker/LocalWorkerFactory.java  |   2 +-
 .../master/localworker/LocalWorkerState.java    |  34 ++---
 .../master/localworker/PersistedState.java      |   4 +-
 .../server/master/localworker/StreamLogger.java |   2 +-
 .../server/master/localworker/package-info.java |   2 +-
 .../master/notification/EmailDispatcher.java    |   2 +-
 .../master/notification/JabberDispatcher.java   |   6 +-
 .../master/notification/NotificationEngine.java |   6 +-
 .../notification/RateLimitedDispatcher.java     |   6 +-
 .../master/notification/SMSDispatcher.java      |   4 +-
 .../master/notification/TwitterDispatcher.java  |   2 +-
 .../master/notification/atom/AtomFeed.java      |  16 +--
 .../server/master/notification/atom/Event.java  |   4 +-
 .../master/notification/atom/EventDAO.java      |  12 +-
 .../master/notification/atom/package-info.java  |  14 +-
 .../master/notification/package-info.java       |   2 +-
 .../taverna/server/master/package-info.java     |   2 +-
 .../server/master/rest/ContentTypes.java        |   2 +-
 .../server/master/rest/DirectoryContents.java   |   8 +-
 .../taverna/server/master/rest/FileSegment.java |   6 +-
 .../server/master/rest/InteractionFeedREST.java |  10 +-
 .../server/master/rest/ListenerDefinition.java  |   2 +-
 .../master/rest/MakeOrUpdateDirEntry.java       |   2 +-
 .../master/rest/TavernaServerDirectoryREST.java |  24 ++--
 .../master/rest/TavernaServerInputREST.java     |  36 ++---
 .../master/rest/TavernaServerListenersREST.java |  22 ++--
 .../server/master/rest/TavernaServerREST.java   |  58 ++++----
 .../master/rest/TavernaServerRunREST.java       |  88 ++++++-------
 .../master/rest/TavernaServerSecurityREST.java  |  46 +++----
 .../rest/handler/AccessDeniedHandler.java       |   2 +-
 .../rest/handler/BadInputPortNameHandler.java   |   4 +-
 .../rest/handler/BadPropertyValueHandler.java   |   4 +-
 .../rest/handler/BadStateChangeHandler.java     |   4 +-
 .../master/rest/handler/EntryHandler.java       |   2 +-
 .../server/master/rest/handler/FeedHandler.java |   2 +-
 .../rest/handler/FileConcatenationHandler.java  |   8 +-
 .../master/rest/handler/FileMessageHandler.java |   6 +-
 .../master/rest/handler/FileSegmentHandler.java |   6 +-
 .../rest/handler/FilesystemAccessHandler.java   |   4 +-
 .../rest/handler/GeneralFailureHandler.java     |   4 +-
 .../server/master/rest/handler/HandlerCore.java |   4 +-
 .../rest/handler/IllegalArgumentHandler.java    |   2 +-
 .../handler/ImplementationProblemHandler.java   |   4 +-
 .../rest/handler/InputStreamMessageHandler.java |   2 +-
 .../rest/handler/InvalidCredentialHandler.java  |   4 +-
 .../rest/handler/JAXBExceptionHandler.java      |   2 +-
 .../rest/handler/NegotiationFailedHandler.java  |   4 +-
 .../master/rest/handler/NoCreateHandler.java    |   4 +-
 .../rest/handler/NoCredentialHandler.java       |   4 +-
 .../master/rest/handler/NoDestroyHandler.java   |   4 +-
 .../rest/handler/NoDirectoryEntryHandler.java   |   4 +-
 .../master/rest/handler/NoListenerHandler.java  |   4 +-
 .../master/rest/handler/NoUpdateHandler.java    |   4 +-
 .../master/rest/handler/NotOwnerHandler.java    |   4 +-
 .../master/rest/handler/OverloadedHandler.java  |   4 +-
 .../master/rest/handler/PermissionHandler.java  |   4 +-
 .../rest/handler/Scufl2DocumentHandler.java     |   4 +-
 .../rest/handler/T2FlowDocumentHandler.java     |   4 +-
 .../master/rest/handler/URIListHandler.java     |   4 +-
 .../master/rest/handler/UnknownRunHandler.java  |   4 +-
 .../master/rest/handler/ZipStreamHandler.java   |   6 +-
 .../master/rest/handler/package-info.java       |  16 +--
 .../server/master/rest/package-info.java        |  16 +--
 .../taverna/server/master/soap/DirEntry.java    |   6 +-
 .../server/master/soap/FileContents.java        |   6 +-
 .../server/master/soap/PermissionList.java      |   4 +-
 .../server/master/soap/TavernaServerSOAP.java   |  56 ++++----
 .../server/master/soap/WrappedWorkflow.java     |   4 +-
 .../server/master/soap/ZippedDirectory.java     |   8 +-
 .../server/master/soap/package-info.java        |  16 +--
 .../server/master/usage/UsageRecord.java        |   2 +-
 .../master/usage/UsageRecordRecorder.java       |   8 +-
 .../server/master/usage/package-info.java       |   2 +-
 .../server/master/utils/CallTimeLogger.java     |   8 +-
 .../server/master/utils/CallTimingFilter.java   |   2 +-
 .../server/master/utils/CapabilityLister.java   |   4 +-
 .../master/utils/CertificateChainFetcher.java   |   2 +-
 .../server/master/utils/Contextualizer.java     |   4 +-
 .../taverna/server/master/utils/DerbyUtils.java |   2 +-
 .../server/master/utils/FilenameUtils.java      |  16 +--
 .../utils/FlushThreadLocalCacheInterceptor.java |   2 +-
 .../server/master/utils/InvocationCounter.java  |   4 +-
 .../taverna/server/master/utils/JCECheck.java   |   2 +-
 .../taverna/server/master/utils/JDOSupport.java |   4 +-
 .../master/utils/LoggingDerbyAdapter.java       |   2 +-
 .../server/master/utils/OneShotThread.java      |   2 +-
 .../taverna/server/master/utils/RestUtils.java  |   2 +-
 .../master/utils/RuntimeExceptionWrapper.java   |   6 +-
 .../server/master/utils/UsernamePrincipal.java  |   2 +-
 .../utils/WSDLHeadOptionsInterceptor.java       |   2 +-
 .../master/utils/WebappAwareDataSource.java     |   4 +-
 .../taverna/server/master/utils/X500Utils.java  |   2 +-
 .../server/master/utils/package-info.java       |   2 +-
 .../master/worker/CompletionNotifier.java       |   2 +-
 .../server/master/worker/FactoryBean.java       |   4 +-
 .../server/master/worker/PasswordIssuer.java    |   2 +-
 .../server/master/worker/PolicyImpl.java        |  22 ++--
 .../server/master/worker/PolicyLimits.java      |   4 +-
 .../server/master/worker/RemoteRunDelegate.java |  60 ++++-----
 .../server/master/worker/RunConnection.java     |  28 ++--
 .../server/master/worker/RunDBSupport.java      |   4 +-
 .../server/master/worker/RunDatabase.java       |  20 +--
 .../server/master/worker/RunDatabaseDAO.java    |  14 +-
 .../master/worker/RunFactoryConfiguration.java  |  10 +-
 .../master/worker/SecurityContextDelegate.java  |  30 ++---
 .../worker/SecurityContextDelegateImpl.java     |  12 +-
 .../master/worker/SecurityContextFactory.java   |  16 +--
 .../SimpleFormattedCompletionNotifier.java      |   4 +-
 .../worker/VelocityCompletionNotifier.java      |  10 +-
 .../server/master/worker/WorkerModel.java       |   4 +-
 .../server/master/worker/package-info.java      |   2 +-
 .../src/main/webapp/META-INF/persistence.xml    |  12 +-
 .../src/main/webapp/WEB-INF/beans.xml           | 120 ++++++++---------
 .../src/main/webapp/WEB-INF/insecure.xml        |   2 +-
 .../src/main/webapp/WEB-INF/partsecure.xml      |   2 +-
 .../src/main/webapp/WEB-INF/providers.xml       |  60 ++++-----
 .../src/main/webapp/WEB-INF/webappBeans.xml     |  10 +-
 .../taverna/server/master/JaxbSanityTest.java   |  72 +++++-----
 .../server/master/TavernaServerImplTest.java    |  26 ++--
 .../master/WorkflowSerializationTest.java       |   8 +-
 .../taverna/server/master/mocks/ExampleRun.java |  38 +++---
 .../taverna/server/master/mocks/MockPolicy.java |  14 +-
 .../master/mocks/SimpleListenerFactory.java     |  10 +-
 .../mocks/SimpleNonpersistentRunStore.java      |  14 +-
 .../server/master/mocks/SimpleServerPolicy.java |  16 +--
 .../src/test/resources/example.xml              |  12 +-
 taverna-server-worker/pom.xml                   |   2 +-
 .../server/localworker/api/Constants.java       |   2 +-
 .../server/localworker/api/RunAccounting.java   |   2 +-
 .../taverna/server/localworker/api/Worker.java  |  12 +-
 .../server/localworker/api/WorkerFactory.java   |   2 +-
 .../localworker/impl/DirectoryDelegate.java     |  10 +-
 .../server/localworker/impl/FileDelegate.java   |   6 +-
 .../server/localworker/impl/LocalWorker.java    |  52 ++++----
 .../localworker/impl/TavernaRunManager.java     |  26 ++--
 .../server/localworker/impl/WorkerCore.java     |  60 ++++-----
 .../impl/utils/FilenameVerifier.java            |   2 +-
 .../localworker/impl/utils/TimingOutTask.java   |   2 +-
 .../localworker/impl/LocalWorkerTest.java       |  22 ++--
 272 files changed, 1470 insertions(+), 1470 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 8aa2d4c..dd76635 100644
--- a/pom.xml
+++ b/pom.xml
@@ -319,39 +319,39 @@ executing.</description>
 					<groups>
 						<group>
 							<title>Server Core WebService</title>
-							<packages>org.taverna.server.master:org.taverna.server.master.common:org.taverna.server.master.facade:org.taverna.server.master.rest:org.taverna.server.master.rest.handler:org.taverna.server.master.soap</packages>
+							<packages>org.apache.taverna.server.master:org.apache.taverna.server.master.common:org.apache.taverna.server.master.facade:org.apache.taverna.server.master.rest:org.apache.taverna.server.master.rest.handler:org.apache.taverna.server.master.soap</packages>
 						</group>
 						<group>
 							<title>Default Values and Administration</title>
-							<packages>org.taverna.server.master.admin:org.taverna.server.master.defaults</packages>
+							<packages>org.apache.taverna.server.master.admin:org.apache.taverna.server.master.defaults</packages>
 						</group>
 						<group>
 							<title>Server SPI</title>
-							<packages>org.taverna.server.master.exceptions:org.taverna.server.master.factories:org.taverna.server.master.interfaces</packages>
+							<packages>org.apache.taverna.server.master.exceptions:org.apache.taverna.server.master.factories:org.apache.taverna.server.master.interfaces</packages>
 						</group>
 						<group>
 							<title>Notification and Accounting</title>
-							<packages>org.taverna.server.master.interaction:org.taverna.server.master.notification:org.taverna.server.master.notification.atom:org.taverna.server.master.usage</packages>
+							<packages>org.apache.taverna.server.master.interaction:org.apache.taverna.server.master.notification:org.apache.taverna.server.master.notification.atom:org.apache.taverna.server.master.usage</packages>
 						</group>
 						<group>
 							<title>Server Coupling to RMI Back End</title>
-							<packages>org.taverna.server.master.identity:org.taverna.server.master.localworker:org.taverna.server.master.worker</packages>
+							<packages>org.apache.taverna.server.master.identity:org.apache.taverna.server.master.localworker:org.apache.taverna.server.master.worker</packages>
 						</group>
 						<group>
 							<title>Server RMI Interface to Back End</title>
-							<packages>org.taverna.server.localworker.remote:org.taverna.server.localworker.server</packages>
+							<packages>org.apache.taverna.server.localworker.remote:org.apache.taverna.server.localworker.server</packages>
 						</group>
 						<group>
 							<title>Externally-Defined Document Formats</title>
-							<packages>org.taverna.server.port_description:org.apache.taverna.server.usagerecord:org.apache.taverna.server.usagerecord.xml.urf:org.apache.taverna.server.usagerecord.xml.dsig</packages>
+							<packages>org.apache.taverna.server.port_description:org.apache.taverna.server.usagerecord:org.apache.taverna.server.usagerecord.xml.urf:org.apache.taverna.server.usagerecord.xml.dsig</packages>
 						</group>
 						<group>
 							<title>Server Back End Factory Coupling to Command Line Executor</title>
-							<packages>org.taverna.server.localworker.impl:org.taverna.server.unixforker:org.taverna.server.winforker</packages>
+							<packages>org.apache.taverna.server.localworker.impl:org.apache.taverna.server.unixforker:org.apache.taverna.server.winforker</packages>
 						</group>
 						<group>
 							<title>Utilities</title>
-							<packages>org.taverna.server.master.utils:org.taverna.server.localworker.impl.utils</packages>
+							<packages>org.apache.taverna.server.master.utils:org.apache.taverna.server.localworker.impl.utils</packages>
 						</group>
 					</groups>
 					<detectJavaApiLink>true</detectJavaApiLink>
@@ -410,39 +410,39 @@ executing.</description>
 							<groups>
 								<group>
 									<title>Server Core WebService</title>
-									<packages>org.taverna.server.master:org.taverna.server.master.common:org.taverna.server.master.facade:org.taverna.server.master.rest:org.taverna.server.master.rest.handler:org.taverna.server.master.soap</packages>
+									<packages>org.apache.taverna.server.master:org.apache.taverna.server.master.common:org.apache.taverna.server.master.facade:org.apache.taverna.server.master.rest:org.apache.taverna.server.master.rest.handler:org.apache.taverna.server.master.soap</packages>
 								</group>
 								<group>
 									<title>Default Values and Administration</title>
-									<packages>org.taverna.server.master.admin:org.taverna.server.master.defaults</packages>
+									<packages>org.apache.taverna.server.master.admin:org.apache.taverna.server.master.defaults</packages>
 								</group>
 								<group>
 									<title>Server SPI</title>
-									<packages>org.taverna.server.master.exceptions:org.taverna.server.master.factories:org.taverna.server.master.interfaces</packages>
+									<packages>org.apache.taverna.server.master.exceptions:org.apache.taverna.server.master.factories:org.apache.taverna.server.master.interfaces</packages>
 								</group>
 								<group>
 									<title>Notification and Accounting</title>
-									<packages>org.taverna.server.master.interaction:org.taverna.server.master.notification:org.taverna.server.master.notification.atom:org.taverna.server.master.usage</packages>
+									<packages>org.apache.taverna.server.master.interaction:org.apache.taverna.server.master.notification:org.apache.taverna.server.master.notification.atom:org.apache.taverna.server.master.usage</packages>
 								</group>
 								<group>
 									<title>Server Coupling to RMI Back End</title>
-									<packages>org.taverna.server.master.identity:org.taverna.server.master.localworker:org.taverna.server.master.worker</packages>
+									<packages>org.apache.taverna.server.master.identity:org.apache.taverna.server.master.localworker:org.apache.taverna.server.master.worker</packages>
 								</group>
 								<group>
 									<title>Server RMI Interface to Back End</title>
-									<packages>org.taverna.server.localworker.remote:org.taverna.server.localworker.server</packages>
+									<packages>org.apache.taverna.server.localworker.remote:org.apache.taverna.server.localworker.server</packages>
 								</group>
 								<group>
 									<title>Externally-Defined Document Formats</title>
-									<packages>org.taverna.server.port_description:org.apache.taverna.server.usagerecord:org.apache.taverna.server.usagerecord.xml.urf:org.apache.taverna.server.usagerecord.xml.dsig</packages>
+									<packages>org.apache.taverna.server.port_description:org.apache.taverna.server.usagerecord:org.apache.taverna.server.usagerecord.xml.urf:org.apache.taverna.server.usagerecord.xml.dsig</packages>
 								</group>
 								<group>
 									<title>Server Back End Factory Coupling to Command Line Executor</title>
-									<packages>org.taverna.server.localworker.impl:org.taverna.server.unixforker:org.taverna.server.winforker</packages>
+									<packages>org.apache.taverna.server.localworker.impl:org.apache.taverna.server.unixforker:org.apache.taverna.server.winforker</packages>
 								</group>
 								<group>
 									<title>Utilities</title>
-									<packages>org.taverna.server.master.utils:org.taverna.server.localworker.impl.utils</packages>
+									<packages>org.apache.taverna.server.master.utils:org.apache.taverna.server.localworker.impl.utils</packages>
 								</group>
 							</groups>
 							<detectJavaApiLink>true</detectJavaApiLink>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbsentValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbsentValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbsentValue.java
index 140d6a5..11d194c 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbsentValue.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbsentValue.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPort.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPort.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPort.java
index 5ed8d70..83374ea 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPort.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPort.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@ 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;
+import org.apache.taverna.server.port_description.utils.IntAdapter;
 
 @XmlType(name = "Port")
 public class AbstractPort {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPortDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPortDescription.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPortDescription.java
index 721e8c8..f70d709 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPortDescription.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractPortDescription.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractValue.java
index 1ded5c7..8a593d0 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractValue.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/AbstractValue.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.port_description;
  * limitations under the License.
  */
 
-import static org.taverna.server.port_description.Namespaces.XLINK;
+import static org.apache.taverna.server.port_description.Namespaces.XLINK;
 
 import java.net.URI;
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ErrorValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ErrorValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ErrorValue.java
index 641c380..81a3f8d 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ErrorValue.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ErrorValue.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@ 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;
+import org.apache.taverna.server.port_description.utils.IntAdapter;
 
 @XmlType(name = "ErrorValue")
 public class ErrorValue extends AbstractValue {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/InputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/InputDescription.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/InputDescription.java
index c11baa1..58184bf 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/InputDescription.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/InputDescription.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,7 +18,7 @@ package org.taverna.server.port_description;
  * limitations under the License.
  */
 
-import static org.taverna.server.port_description.Namespaces.XLINK;
+import static org.apache.taverna.server.port_description.Namespaces.XLINK;
 
 import java.net.URI;
 import java.util.ArrayList;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/LeafValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/LeafValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/LeafValue.java
index 95658bc..995aa1a 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/LeafValue.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/LeafValue.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ListValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ListValue.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ListValue.java
index f3e8ff1..a4077dd 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ListValue.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/ListValue.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -28,7 +28,7 @@ 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;
+import org.apache.taverna.server.port_description.utils.IntAdapter;
 
 @XmlType(name = "ListValue")
 public class ListValue extends AbstractValue {

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/Namespaces.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/Namespaces.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/Namespaces.java
index f60e6c4..11ab63d 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/Namespaces.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/Namespaces.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/OutputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/OutputDescription.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/OutputDescription.java
index 2f402d1..0c13db8 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/OutputDescription.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/OutputDescription.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/package-info.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/package-info.java
index 76228db..2df4403 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/package-info.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/package-info.java
@@ -4,7 +4,7 @@
 		@XmlNs(prefix = "port", namespaceURI = DATA),
 		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
 		@XmlNs(prefix = "run", namespaceURI = RUN) })
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,9 +23,9 @@ 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 static org.apache.taverna.server.port_description.Namespaces.DATA;
+import static org.apache.taverna.server.port_description.Namespaces.RUN;
+import static org.apache.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/46777e2c/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/utils/IntAdapter.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/utils/IntAdapter.java b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/utils/IntAdapter.java
index de9a3a8..1e3bddc 100644
--- a/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/utils/IntAdapter.java
+++ b/taverna-server-port-description/src/main/java/org/apache/taverna/server/port_description/utils/IntAdapter.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.port_description.utils;
+package org.apache.taverna.server.port_description.utils;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-port-description/src/test/java/org/apache/taverna/server/port_description/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/test/java/org/apache/taverna/server/port_description/JaxbSanityTest.java b/taverna-server-port-description/src/test/java/org/apache/taverna/server/port_description/JaxbSanityTest.java
index de15cfa..122956f 100644
--- a/taverna-server-port-description/src/test/java/org/apache/taverna/server/port_description/JaxbSanityTest.java
+++ b/taverna-server-port-description/src/test/java/org/apache/taverna/server/port_description/JaxbSanityTest.java
@@ -1,4 +1,4 @@
-package org.taverna.server.port_description;
+package org.apache.taverna.server.port_description;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-rmidaemon/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/pom.xml b/taverna-server-rmidaemon/pom.xml
index 8058497..35784c8 100644
--- a/taverna-server-rmidaemon/pom.xml
+++ b/taverna-server-rmidaemon/pom.xml
@@ -29,7 +29,7 @@ limitations under the License.
 
 	<properties>
 		<project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
-		<mainClass>org.taverna.server.rmidaemon.Registry</mainClass>
+		<mainClass>org.apache.taverna.server.rmidaemon.Registry</mainClass>
 	</properties>
 	<build>
 		<plugins>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/Registry.java
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/Registry.java b/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/Registry.java
index 333153f..6e804d0 100644
--- a/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/Registry.java
+++ b/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/Registry.java
@@ -1,4 +1,4 @@
-package org.taverna.server.rmidaemon;
+package org.apache.taverna.server.rmidaemon;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/package-info.java b/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/package-info.java
index 520b928..a7db743 100644
--- a/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/package-info.java
+++ b/taverna-server-rmidaemon/src/main/java/org/apache/taverna/server/rmidaemon/package-info.java
@@ -2,7 +2,7 @@
  * RMI daemon implementation. A variation of an RMI registry.
  * @author Donal Fellows
  */
-package org.taverna.server.rmidaemon;
+package org.apache.taverna.server.rmidaemon;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/IllegalStateTransitionException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/IllegalStateTransitionException.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/IllegalStateTransitionException.java
index cb0cc0a..d2cb2a0 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/IllegalStateTransitionException.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/IllegalStateTransitionException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/ImplementationException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/ImplementationException.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/ImplementationException.java
index 3e33fc7..056b87e 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/ImplementationException.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/ImplementationException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectory.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectory.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectory.java
index 229d0b7..c0bb15f 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectory.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectoryEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectoryEntry.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectoryEntry.java
index 9b77e79..11f096e 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectoryEntry.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteDirectoryEntry.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteFile.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteFile.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteFile.java
index 63778db..8632306 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteFile.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteFile.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteInput.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteInput.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteInput.java
index b4fda9e..94accde 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteInput.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteInput.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteListener.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteListener.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteListener.java
index 2539f0d..11b6867 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteListener.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteListener.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteRunFactory.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteRunFactory.java
index bc91f0e..75ad94f 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteRunFactory.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteRunFactory.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,7 +22,7 @@ import java.rmi.Remote;
 import java.rmi.RemoteException;
 import java.util.UUID;
 
-import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.apache.taverna.server.localworker.server.UsageRecordReceiver;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSecurityContext.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSecurityContext.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSecurityContext.java
index fc4baff..149ae66 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSecurityContext.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSecurityContext.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSingleRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSingleRun.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSingleRun.java
index e2519f8..62e7b3f 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSingleRun.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteSingleRun.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteStatus.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteStatus.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteStatus.java
index 89a7cff..88b4e7a 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteStatus.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/RemoteStatus.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/StillWorkingOnItException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/StillWorkingOnItException.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/StillWorkingOnItException.java
index a7af96b..a53ff3a 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/StillWorkingOnItException.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/StillWorkingOnItException.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/package-info.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/package-info.java
index 6466e2f..870d6cc 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/package-info.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/remote/package-info.java
@@ -3,7 +3,7 @@
 /**
  * Interfaces exported by worker classes to the server.
  */
-package org.taverna.server.localworker.remote;
+package org.apache.taverna.server.localworker.remote;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/UsageRecordReceiver.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/UsageRecordReceiver.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/UsageRecordReceiver.java
index cc0127e..42d9089 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/UsageRecordReceiver.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/UsageRecordReceiver.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.localworker.server;
+package org.apache.taverna.server.localworker.server;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/package-info.java b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/package-info.java
index 584f1ed..ef14688 100644
--- a/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/package-info.java
+++ b/taverna-server-runinterface/src/main/java/org/apache/taverna/server/localworker/server/package-info.java
@@ -3,7 +3,7 @@
 /**
  * Interfaces exported by the server to worker classes.
  */
-package org.taverna.server.localworker.server;
+package org.apache.taverna.server.localworker.server;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-unix-forker/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-unix-forker/pom.xml b/taverna-server-unix-forker/pom.xml
index f7f61ef..7f0e113 100644
--- a/taverna-server-unix-forker/pom.xml
+++ b/taverna-server-unix-forker/pom.xml
@@ -28,7 +28,7 @@ limitations under the License.
 
 	<properties>
 		<project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
-		<forkerMainClass>org.taverna.server.unixforker.Forker</forkerMainClass>
+		<forkerMainClass>org.apache.taverna.server.unixforker.Forker</forkerMainClass>
 	</properties>
 
 	<build>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-unix-forker/src/main/java/org/apache/taverna/server/unixforker/Forker.java
----------------------------------------------------------------------
diff --git a/taverna-server-unix-forker/src/main/java/org/apache/taverna/server/unixforker/Forker.java b/taverna-server-unix-forker/src/main/java/org/apache/taverna/server/unixforker/Forker.java
index ebe73f4..6502078 100644
--- a/taverna-server-unix-forker/src/main/java/org/apache/taverna/server/unixforker/Forker.java
+++ b/taverna-server-unix-forker/src/main/java/org/apache/taverna/server/unixforker/Forker.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.unixforker;
+package org.apache.taverna.server.unixforker;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/pom.xml b/taverna-server-webapp/pom.xml
index 2b804df..e8ed5d7 100644
--- a/taverna-server-webapp/pom.xml
+++ b/taverna-server-webapp/pom.xml
@@ -539,12 +539,12 @@ limitations under the License.
 				<configuration>
 					<fork>false</fork>
 					<metadataIncludes>
-						org/taverna/server/master/*.class,
-						org/taverna/server/master/identity/*.class,
-						org/taverna/server/master/localworker/*.class,
-						org/taverna/server/master/notification/atom/*.class,
-						org/taverna/server/master/usage/*.class,
-						org/taverna/server/master/worker/*.class
+						org.apache.taverna/server/master/*.class,
+						org.apache.taverna/server/master/identity/*.class,
+						org.apache.taverna/server/master/localworker/*.class,
+						org.apache.taverna/server/master/notification/atom/*.class,
+						org.apache.taverna/server/master/usage/*.class,
+						org.apache.taverna/server/master/worker/*.class
 					</metadataIncludes>
 				</configuration>
 				<executions>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ContentsDescriptorBuilder.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ContentsDescriptorBuilder.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ContentsDescriptorBuilder.java
index 051a037..c9beb9c 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ContentsDescriptorBuilder.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ContentsDescriptorBuilder.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,7 +22,7 @@ import static eu.medsea.util.MimeUtil.getMimeType;
 import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
 import static javax.ws.rs.core.UriBuilder.fromUri;
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.common.Uri.secure;
+import static org.apache.taverna.server.master.common.Uri.secure;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -36,24 +36,24 @@ import javax.ws.rs.core.UriInfo;
 
 import org.apache.commons.logging.Log;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.port_description.AbsentValue;
-import org.taverna.server.port_description.AbstractPortDescription;
-import org.taverna.server.port_description.AbstractValue;
-import org.taverna.server.port_description.ErrorValue;
-import org.taverna.server.port_description.InputDescription;
-import org.taverna.server.port_description.InputDescription.InputPort;
-import org.taverna.server.port_description.LeafValue;
-import org.taverna.server.port_description.ListValue;
-import org.taverna.server.port_description.OutputDescription;
-import org.taverna.server.port_description.OutputDescription.OutputPort;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.interfaces.DirectoryEntry;
+import org.apache.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.interfaces.UriBuilderFactory;
+import org.apache.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.port_description.AbsentValue;
+import org.apache.taverna.server.port_description.AbstractPortDescription;
+import org.apache.taverna.server.port_description.AbstractValue;
+import org.apache.taverna.server.port_description.ErrorValue;
+import org.apache.taverna.server.port_description.InputDescription;
+import org.apache.taverna.server.port_description.InputDescription.InputPort;
+import org.apache.taverna.server.port_description.LeafValue;
+import org.apache.taverna.server.port_description.ListValue;
+import org.apache.taverna.server.port_description.OutputDescription;
+import org.apache.taverna.server.port_description.OutputDescription.OutputPort;
 
 import org.apache.taverna.scufl2.api.container.WorkflowBundle;
 import org.apache.taverna.scufl2.api.core.Workflow;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/DirectoryREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/DirectoryREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/DirectoryREST.java
index b800c1c..f34c042 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/DirectoryREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/DirectoryREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,13 +25,13 @@ import static javax.ws.rs.core.Response.ok;
 import static javax.ws.rs.core.Response.seeOther;
 import static javax.ws.rs.core.Response.status;
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
-import static org.taverna.server.master.api.ContentTypes.DIRECTORY_VARIANTS;
-import static org.taverna.server.master.api.ContentTypes.INITIAL_FILE_VARIANTS;
-import static org.taverna.server.master.common.Roles.SELF;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
+import static org.apache.taverna.server.master.api.ContentTypes.DIRECTORY_VARIANTS;
+import static org.apache.taverna.server.master.api.ContentTypes.INITIAL_FILE_VARIANTS;
+import static org.apache.taverna.server.master.common.Roles.SELF;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.common.Uri.secure;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -52,22 +52,22 @@ import javax.xml.ws.Holder;
 
 import org.apache.commons.logging.Log;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.DirectoryBean;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.DirectoryContents;
-import org.taverna.server.master.rest.FileSegment;
-import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
-import org.taverna.server.master.rest.MakeOrUpdateDirEntry.MakeDirectory;
-import org.taverna.server.master.rest.TavernaServerDirectoryREST;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.master.api.DirectoryBean;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.Directory;
+import org.apache.taverna.server.master.interfaces.DirectoryEntry;
+import org.apache.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.DirectoryContents;
+import org.apache.taverna.server.master.rest.FileSegment;
+import org.apache.taverna.server.master.rest.MakeOrUpdateDirEntry;
+import org.apache.taverna.server.master.rest.MakeOrUpdateDirEntry.MakeDirectory;
+import org.apache.taverna.server.master.rest.TavernaServerDirectoryREST;
+import org.apache.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
 
 /**
  * RESTful access to the filesystem.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/FileConcatenation.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/FileConcatenation.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/FileConcatenation.java
index 4ccb033..512adc1 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/FileConcatenation.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/FileConcatenation.java
@@ -1,4 +1,4 @@
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,8 +23,8 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.interfaces.File;
 
 /**
  * Simple concatenation of files.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InputREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InputREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InputREST.java
index b9c8f55..76e21d9 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InputREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InputREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,7 +19,7 @@ package org.taverna.server.master;
  */
 
 import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import java.util.Date;
 
@@ -31,26 +31,26 @@ import javax.ws.rs.core.UriInfo;
 import org.apache.cxf.jaxrs.impl.MetadataMap;
 import org.apache.cxf.jaxrs.model.URITemplate;
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.InputBean;
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.exceptions.BadInputPortNameException;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerInputREST;
-import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.AbstractContents;
-import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.Reference;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-import org.taverna.server.port_description.InputDescription;
+import org.apache.taverna.server.master.api.InputBean;
+import org.apache.taverna.server.master.common.DirEntryReference;
+import org.apache.taverna.server.master.exceptions.BadInputPortNameException;
+import org.apache.taverna.server.master.exceptions.BadPropertyValueException;
+import org.apache.taverna.server.master.exceptions.BadStateChangeException;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.exceptions.UnknownRunException;
+import org.apache.taverna.server.master.interfaces.DirectoryEntry;
+import org.apache.taverna.server.master.interfaces.File;
+import org.apache.taverna.server.master.interfaces.Input;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.TavernaServerInputREST;
+import org.apache.taverna.server.master.rest.TavernaServerInputREST.InDesc.AbstractContents;
+import org.apache.taverna.server.master.rest.TavernaServerInputREST.InDesc.Reference;
+import org.apache.taverna.server.master.utils.FilenameUtils;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.port_description.InputDescription;
 
 /**
  * RESTful interface to the input descriptor of a single workflow run.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InteractionFeed.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InteractionFeed.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InteractionFeed.java
index 6dfa3e2..5ee0253 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InteractionFeed.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/InteractionFeed.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,9 +18,9 @@ package org.taverna.server.master;
  * limitations under the License.
  */
 
-import static org.taverna.server.master.common.Roles.SELF;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.common.Roles.SELF;
+import static org.apache.taverna.server.master.common.Roles.USER;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import java.net.MalformedURLException;
 import java.net.URI;
@@ -31,15 +31,15 @@ import javax.ws.rs.core.Response;
 
 import org.apache.abdera.model.Entry;
 import org.apache.abdera.model.Feed;
-import org.taverna.server.master.api.FeedBean;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interaction.InteractionFeedSupport;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.InteractionFeedREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.master.api.FeedBean;
+import org.apache.taverna.server.master.exceptions.FilesystemAccessException;
+import org.apache.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interaction.InteractionFeedSupport;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.InteractionFeedREST;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
 
 /**
  * How to connect an interaction feed to the webapp.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenerPropertyREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenerPropertyREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenerPropertyREST.java
index 26a8982..039325e 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenerPropertyREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenerPropertyREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -19,19 +19,19 @@ package org.taverna.server.master;
  */
 
 import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import javax.ws.rs.core.Response;
 
 import org.apache.commons.logging.Log;
-import org.taverna.server.master.api.ListenerPropertyBean;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.master.api.ListenerPropertyBean;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
 
 /**
  * RESTful interface to a single property of a workflow run.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenersREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenersREST.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenersREST.java
index 3cc0d73..2fabb8d 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenersREST.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ListenersREST.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -20,8 +20,8 @@ package org.taverna.server.master;
 
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
+import static org.apache.taverna.server.master.common.Uri.secure;
+import static org.apache.taverna.server.master.utils.RestUtils.opt;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -31,15 +31,15 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 
-import org.taverna.server.master.api.ListenersBean;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.ListenerDefinition;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.apache.taverna.server.master.api.ListenersBean;
+import org.apache.taverna.server.master.exceptions.NoListenerException;
+import org.apache.taverna.server.master.exceptions.NoUpdateException;
+import org.apache.taverna.server.master.interfaces.Listener;
+import org.apache.taverna.server.master.interfaces.TavernaRun;
+import org.apache.taverna.server.master.rest.ListenerDefinition;
+import org.apache.taverna.server.master.rest.TavernaServerListenersREST;
+import org.apache.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.apache.taverna.server.master.utils.InvocationCounter.CallCounted;
 
 /**
  * RESTful interface to a single workflow run's event listeners.

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/46777e2c/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ManagementState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ManagementState.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ManagementState.java
index c65a334..1a328f6 100644
--- a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ManagementState.java
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/ManagementState.java
@@ -1,6 +1,6 @@
 /*
  */
-package org.taverna.server.master;
+package org.apache.taverna.server.master;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -26,8 +26,8 @@ import javax.jdo.annotations.Persistent;
 import javax.jdo.annotations.PrimaryKey;
 
 import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.utils.JDOSupport;
+import org.apache.taverna.server.master.api.ManagementModel;
+import org.apache.taverna.server.master.utils.JDOSupport;
 
 /** The persistent, manageable state of the Taverna Server web application. */
 @PersistenceAware


[31/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ContentTypes.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ContentTypes.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ContentTypes.java
new file mode 100644
index 0000000..2ad6063
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ContentTypes.java
@@ -0,0 +1,63 @@
+/*
+ */
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE;
+
+import java.util.List;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Variant;
+
+/**
+ * The content types supported at various points in the REST interface.
+ * 
+ * @author Donal Fellows
+ */
+public interface ContentTypes {
+	/** "application/zip" */
+	public static final MediaType APPLICATION_ZIP_TYPE = new MediaType(
+			"application", "zip");
+
+	/** "application/vnd.taverna.baclava+xml" */
+	public static final MediaType BACLAVA_MEDIA_TYPE = new MediaType(
+			"application", "vnd.taverna.baclava+xml");
+
+	/**
+	 * The media types that we are willing to serve up directories as. Note that
+	 * we <i>only</i> serve directories up as these.
+	 */
+	public static final List<Variant> DIRECTORY_VARIANTS = asList(new Variant(
+			APPLICATION_XML_TYPE, (String) null, "UTF-8"), new Variant(
+			APPLICATION_JSON_TYPE, (String) null, "UTF-8"), new Variant(
+			APPLICATION_ZIP_TYPE, (String) null, null));
+
+	/**
+	 * The baseline set of media types that we are willing to serve up files as.
+	 * Note that we <i>also</i> serve files up as their auto-detected media
+	 * type. In all cases, this means we just shovel the bytes (or characters,
+	 * in the case of <tt>text/*</tt> subtypes) back at the client.
+	 */
+	public static final List<Variant> INITIAL_FILE_VARIANTS = singletonList(new Variant(
+			APPLICATION_OCTET_STREAM_TYPE, (String) null, null));
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/DirectoryBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/DirectoryBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/DirectoryBean.java
new file mode 100644
index 0000000..7cb1b7e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/DirectoryBean.java
@@ -0,0 +1,32 @@
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.rest.TavernaServerDirectoryREST;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.FilenameUtils;
+
+/**
+ * Description of properties supported by {@link DirectoryREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface DirectoryBean extends SupportAware {
+	void setFileUtils(FilenameUtils fileUtils);
+
+	TavernaServerDirectoryREST connect(TavernaRun run);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/FeedBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/FeedBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/FeedBean.java
new file mode 100644
index 0000000..c977974
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/FeedBean.java
@@ -0,0 +1,29 @@
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.InteractionFeed;
+import org.taverna.server.master.interaction.InteractionFeedSupport;
+
+/**
+ * Description of properties supported by {@link InteractionFeed}.
+ * 
+ * @author Donal Fellows
+ */
+public interface FeedBean {
+	void setInteractionFeedSupport(InteractionFeedSupport feed);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/InputBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/InputBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/InputBean.java
new file mode 100644
index 0000000..17003e5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/InputBean.java
@@ -0,0 +1,37 @@
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import javax.ws.rs.core.UriInfo;
+
+import org.taverna.server.master.ContentsDescriptorBuilder;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerInputREST;
+import org.taverna.server.master.utils.FilenameUtils;
+
+/**
+ * Description of properties supported by {@link org.taverna.server.master.InputREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface InputBean extends SupportAware {
+	TavernaServerInputREST connect(TavernaRun run, UriInfo ui);
+
+	void setCdBuilder(ContentsDescriptorBuilder cd);
+
+	void setFileUtils(FilenameUtils fn);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenerPropertyBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenerPropertyBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenerPropertyBean.java
new file mode 100644
index 0000000..52a52f2
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenerPropertyBean.java
@@ -0,0 +1,31 @@
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+
+/**
+ * Description of properties supported by {@link ListenerPropertyREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface ListenerPropertyBean extends SupportAware {
+	TavernaServerListenersREST.Property connect(Listener listen,
+			TavernaRun run, String propertyName);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenersBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenersBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenersBean.java
new file mode 100644
index 0000000..63035f7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ListenersBean.java
@@ -0,0 +1,29 @@
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+
+/**
+ * Description of properties supported by {@link ListenersREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface ListenersBean extends SupportAware {
+	TavernaServerListenersREST connect(TavernaRun run);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ManagementModel.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ManagementModel.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ManagementModel.java
new file mode 100644
index 0000000..dc02279
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/ManagementModel.java
@@ -0,0 +1,74 @@
+/*
+ */
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+/**
+ * The model of the webapp's state Java Bean.
+ * 
+ * @author Donal Fellows
+ */
+public interface ManagementModel {
+	/**
+	 * @return whether we allow the creation of new workflow runs.
+	 */
+	boolean getAllowNewWorkflowRuns();
+
+	/**
+	 * @return whether we should log all workflows sent to us.
+	 */
+	boolean getLogIncomingWorkflows();
+
+	/**
+	 * @return whether outgoing exceptions should be logged before being
+	 *         converted to responses.
+	 */
+	boolean getLogOutgoingExceptions();
+
+	/**
+	 * @return the file that all usage records should be appended to, or
+	 *         <tt>null</tt> if they should be just dropped.
+	 */
+	String getUsageRecordLogFile();
+
+	/**
+	 * @param logIncomingWorkflows
+	 *            whether we should log all workflows sent to us.
+	 */
+	void setLogIncomingWorkflows(boolean logIncomingWorkflows);
+
+	/**
+	 * @param allowNewWorkflowRuns
+	 *            whether we allow the creation of new workflow runs.
+	 */
+	void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns);
+
+	/**
+	 * @param logOutgoingExceptions
+	 *            whether outgoing exceptions should be logged before being
+	 *            converted to responses.
+	 */
+	void setLogOutgoingExceptions(boolean logOutgoingExceptions);
+
+	/**
+	 * @param usageRecordLogFile
+	 *            the file that all usage records should be appended to, or
+	 *            <tt>null</tt> if they should be just dropped.
+	 */
+	void setUsageRecordLogFile(String usageRecordLogFile);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/OneListenerBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/OneListenerBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/OneListenerBean.java
new file mode 100644
index 0000000..f7a7134
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/OneListenerBean.java
@@ -0,0 +1,30 @@
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
+
+/**
+ * Description of properties supported by {@link InputREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface OneListenerBean {
+	TavernaServerListenerREST connect(Listener listen, TavernaRun run);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/RunBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/RunBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/RunBean.java
new file mode 100644
index 0000000..274d9f0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/RunBean.java
@@ -0,0 +1,33 @@
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.ContentsDescriptorBuilder;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * Description of properties supported by {@link org.taverna.server.master.RunREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface RunBean extends SupportAware {
+	void setCdBuilder(ContentsDescriptorBuilder cdBuilder);
+
+	void setRun(TavernaRun run);
+
+	void setRunName(String runName);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SecurityBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SecurityBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SecurityBean.java
new file mode 100644
index 0000000..ddbc9b9
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SecurityBean.java
@@ -0,0 +1,30 @@
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.rest.TavernaServerSecurityREST;
+
+/**
+ * Description of properties supported by {@link RunSecurityREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface SecurityBean extends SupportAware {
+	TavernaServerSecurityREST connect(TavernaSecurityContext context, TavernaRun run);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SupportAware.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SupportAware.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SupportAware.java
new file mode 100644
index 0000000..117533f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/SupportAware.java
@@ -0,0 +1,37 @@
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.TavernaServerSupport;
+
+/**
+ * Indicates that this is a class that wants to be told by Spring about the
+ * main support bean.
+ * 
+ * @author Donal Fellows
+ */
+public interface SupportAware {
+	/**
+	 * How to tell the bean about the support bean.
+	 * 
+	 * @param support
+	 *            Reference to the support bean.
+	 */
+	@Required
+	void setSupport(TavernaServerSupport support);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/TavernaServerBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/TavernaServerBean.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/TavernaServerBean.java
new file mode 100644
index 0000000..8873857
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/TavernaServerBean.java
@@ -0,0 +1,114 @@
+/*
+ */
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */
+
+import javax.annotation.Nonnull;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.ContentsDescriptorBuilder;
+import org.taverna.server.master.TavernaServerSupport;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.RunStore;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.notification.NotificationEngine;
+import org.taverna.server.master.notification.atom.EventDAO;
+import org.taverna.server.master.rest.TavernaServerREST;
+import org.taverna.server.master.soap.TavernaServerSOAP;
+import org.taverna.server.master.utils.FilenameUtils;
+
+/**
+ * The methods of the webapp that are accessed by beans other than itself or
+ * those which are told directly about it. This exists so that an AOP proxy can
+ * be installed around it.
+ * 
+ * @author Donal Fellows
+ */
+public interface TavernaServerBean extends TavernaServerSOAP, TavernaServerREST,
+		UriBuilderFactory {
+	/**
+	 * @param policy
+	 *            The policy being installed by Spring.
+	 */
+	@Required
+	void setPolicy(@Nonnull Policy policy);
+
+	/**
+	 * @param runStore
+	 *            The run store being installed by Spring.
+	 */
+	@Required
+	void setRunStore(@Nonnull RunStore runStore);
+
+	/**
+	 * @param converter
+	 *            The filename converter being installed by Spring.
+	 */
+	@Required
+	void setFileUtils(@Nonnull FilenameUtils converter);
+
+	/**
+	 * @param cdBuilder
+	 *            The contents descriptor builder being installed by Spring.
+	 */
+	@Required
+	void setContentsDescriptorBuilder(
+			@Nonnull ContentsDescriptorBuilder cdBuilder);
+
+	/**
+	 * @param notificationEngine
+	 *            The notification engine being installed by Spring.
+	 */
+	@Required
+	void setNotificationEngine(@Nonnull NotificationEngine notificationEngine);
+
+	/**
+	 * @param support
+	 *            The support bean being installed by Spring.
+	 */
+	@Required
+	void setSupport(@Nonnull TavernaServerSupport support);
+
+	/**
+	 * @param eventSource
+	 *            The event source bean being installed by Spring.
+	 */
+	@Required
+	void setEventSource(@Nonnull EventDAO eventSource);
+
+	/**
+	 * The nastier parts of security initialisation in SOAP calls, which we want
+	 * to go away.
+	 * 
+	 * @param context
+	 *            The context to configure.
+	 * @return True if we did <i>not</i> initialise things.
+	 */
+	boolean initObsoleteSOAPSecurity(@Nonnull TavernaSecurityContext context);
+
+	/**
+	 * The nastier parts of security initialisation in REST calls, which we want
+	 * to go away.
+	 * 
+	 * @param context
+	 *            The context to configure.
+	 * @return True if we did <i>not</i> initialise things.
+	 */
+	boolean initObsoleteRESTSecurity(@Nonnull TavernaSecurityContext context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/package-info.java
new file mode 100644
index 0000000..0966e24
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/api/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * API <tt>interface</tt>s for the main service classes.
+ * 
+ * @author Donal Fellows
+ */
+package org.taverna.server.master.api;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Capability.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Capability.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Capability.java
new file mode 100644
index 0000000..75f9549
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Capability.java
@@ -0,0 +1,38 @@
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Describes a single capability supported by Taverna Server's workflow
+ * execution core.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "Capability")
+public class Capability {
+	@XmlAttribute
+	@XmlSchemaType(name = "anyURI")
+	public URI capability;
+	@XmlAttribute
+	public String version;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Credential.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Credential.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Credential.java
new file mode 100644
index 0000000..c6627da
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Credential.java
@@ -0,0 +1,162 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.security.Key;
+import java.security.cert.Certificate;
+
+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.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A description of a private credential. This description is characterised by a
+ * file visible to the workflow run that contains a particular key-pair.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "CredentialDescriptor")
+@XmlSeeAlso({ Credential.KeyPair.class, Credential.Password.class })
+@SuppressWarnings("serial")
+public abstract class Credential implements Serializable {
+	/** The location of this descriptor in the REST world. */
+	@XmlAttribute(namespace = XLINK)
+	public String href;
+	/**
+	 * The location of this descriptor in the SOAP world. Must match corrected
+	 * with the {@link #href} field.
+	 */
+	@XmlTransient
+	public String id;
+	/**
+	 * The service URI to use this credential with. If omitted, this represents
+	 * the <i>default</i> credential to use.
+	 */
+	@XmlElement
+	@XmlSchemaType(name = "anyURI")
+	public URI serviceURI;
+	/** The key extracted from the keystore. */
+	public transient Key loadedKey;
+	/** The trust chain of the key extracted from the keystore. */
+	public transient Certificate[] loadedTrustChain;
+
+	@Override
+	public int hashCode() {
+		return id.hashCode();
+	}
+
+	@Override
+	public final boolean equals(Object o) {
+		if (o == null || !(o instanceof Credential))
+			return false;
+		return equals((Credential) o);
+	}
+
+	protected boolean equals(@Nonnull Credential c) {
+		return id.equals(c.id);
+	}
+
+	/**
+	 * A description of a credential that is a public/private key-pair in some
+	 * kind of key store.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "keypair")
+	@XmlType(name = "KeyPairCredential")
+	public static class KeyPair extends Credential {
+		/** The name of the credential within its store, i.e., it's alias. */
+		@XmlElement(required = true)
+		public String credentialName;
+		/**
+		 * The keystore file containing the credential. This is resolved with
+		 * respect to the workflow run working directory.
+		 */
+		@XmlElement
+		public String credentialFile;
+		/**
+		 * The type of keystore file. Defaults to <tt>JKS</tt> if unspecified.
+		 */
+		@XmlElement
+		public String fileType;
+		/**
+		 * The password used to unlock the keystore file. It is assumed that the
+		 * same password is used for unlocking the credential within, or that
+		 * the inner password is empty.
+		 */
+		@XmlElement
+		public String unlockPassword;
+		/**
+		 * The encoded serialized keystore containing the credential.
+		 */
+		@XmlElement
+		public byte[] credentialBytes;
+
+		@Override
+		public String toString() {
+			return "keypair(id=" + id + ")";
+		}
+	}
+
+	/**
+	 * A description of a credential that is a username and password.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "userpass")
+	@XmlType(name = "PasswordCredential")
+	public static class Password extends Credential {
+		@XmlElement(required = true)
+		public String username;
+		@XmlElement(required = true)
+		public String password;
+
+		@Override
+		public String toString() {
+			return "userpass(id=" + id + ")";
+		}
+	}
+
+	/**
+	 * A credential that is just used for deleting credentials by ID. Cannot be
+	 * marshalled as XML.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public static class Dummy extends Credential {
+		public Dummy(String id) {
+			this.id = id;
+		}
+
+		@Override
+		public String toString() {
+			return "dummy(id=" + id + ")";
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/DirEntryReference.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/DirEntryReference.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/DirEntryReference.java
new file mode 100644
index 0000000..424e32a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/DirEntryReference.java
@@ -0,0 +1,106 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.net.URI;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+
+/**
+ * A reference to something that is in a directory below the working directory
+ * of a workflow run, described using JAXB. Note that when creating an XML
+ * document containing one of these in a client, it is <i>not</i> necessary to
+ * supply any attribute.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "DirectoryEntry")
+@XmlSeeAlso( { DirEntryReference.DirectoryReference.class,
+		DirEntryReference.FileReference.class })
+public class DirEntryReference {
+	/** A link to the entry. Ignored on input. */
+	@XmlAttribute(name = "href", namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI link;
+	/** The last, user-displayable part of the name. Ignored on input. */
+	@XmlAttribute
+	public String name;
+	/** The path of the entry. */
+	@XmlValue
+	public String path;
+
+	/**
+	 * Return the directory entry reference instance subclass suitable for the
+	 * given directory entry.
+	 * 
+	 * @param entry
+	 *            The entry to characterise.
+	 * @return An object that describes the directory entry.
+	 */
+	public static DirEntryReference newInstance(DirectoryEntry entry) {
+		return newInstance(null, entry);
+	}
+
+	/**
+	 * Return the directory entry reference instance subclass suitable for the
+	 * given directory entry.
+	 * 
+	 * @param ub
+	 *            Used for constructing URIs. The {@link #link} field is not
+	 *            filled in if this is <tt>null</tt>.
+	 * @param entry
+	 *            The entry to characterise.
+	 * @return An object that describes the directory entry.
+	 */
+	// Really returns a subclass, so cannot be constructor
+	public static DirEntryReference newInstance(UriBuilder ub,
+			DirectoryEntry entry) {
+		DirEntryReference de = (entry instanceof Directory) ? new DirectoryReference()
+				: new FileReference();
+		de.name = entry.getName();
+		String fullname = entry.getFullName();
+		de.path = fullname.startsWith("/") ? fullname.substring(1) : fullname;
+		if (ub != null)
+			de.link = ub.build(entry.getName());
+		return de;
+	}
+
+	/** A reference to a directory, done with JAXB. */
+	@XmlRootElement(name = "dir")
+	@XmlType(name = "DirectoryReference")
+	public static class DirectoryReference extends DirEntryReference {
+	}
+
+	/** A reference to a file, done with JAXB. */
+	@XmlRootElement(name = "file")
+	@XmlType(name = "FileReference")
+	public static class FileReference extends DirEntryReference {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/InputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/InputDescription.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/InputDescription.java
new file mode 100644
index 0000000..b1eb55c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/InputDescription.java
@@ -0,0 +1,123 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+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.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.taverna.server.master.interfaces.Input;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * A description of the inputs to a workflow, described using JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement(name = "inputConfiguration")
+@XmlType(name = "InputConfigurationDescription")
+public class InputDescription extends VersionedElement {
+	/**
+	 * The Baclava file handling the description of the elements. May be
+	 * omitted/<tt>null</tt>.
+	 */
+	@XmlElement(required = false)
+	public String baclavaFile;
+	/**
+	 * The port/value assignment.
+	 */
+	@XmlElement(nillable = false)
+	public List<Port> port = new ArrayList<>();
+
+	/**
+	 * Make a blank input description.
+	 */
+	public InputDescription() {
+	}
+
+	/**
+	 * Make an input description suitable for the given workflow run.
+	 * 
+	 * @param run
+	 */
+	public InputDescription(TavernaRun run) {
+		super(true);
+		baclavaFile = run.getInputBaclavaFile();
+		if (baclavaFile == null)
+			for (Input i : run.getInputs())
+				port.add(new Port(i));
+	}
+
+	/**
+	 * The type of a single port description.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlType(name = "PortConfigurationDescription")
+	public static class Port {
+		/**
+		 * The name of this port.
+		 */
+		@XmlAttribute(name = "portName", required = true)
+		public String name;
+		/**
+		 * The file assigned to this port.
+		 */
+		@XmlAttribute(name = "portFile", required = false)
+		public String file;
+		/**
+		 * The file assigned to this port.
+		 */
+		@XmlAttribute(name = "listDelimiter", required = false)
+		public String delimiter;
+		/**
+		 * The value assigned to this port.
+		 */
+		@XmlValue
+		public String value;
+
+		/**
+		 * Make a blank port description.
+		 */
+		public Port() {
+		}
+
+		/**
+		 * Make a port description suitable for the given input.
+		 * 
+		 * @param input
+		 */
+		public Port(Input input) {
+			name = input.getName();
+			if (input.getFile() != null) {
+				file = input.getFile();
+				value = "";
+			} else {
+				file = null;
+				value = input.getValue();
+			}
+			delimiter = input.getDelimiter();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Namespaces.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Namespaces.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Namespaces.java
new file mode 100644
index 0000000..d2035ee
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Namespaces.java
@@ -0,0 +1,52 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+/**
+ * A convenient place to keep the names of URIs so that they can be got right
+ * <i>once</i>.
+ * 
+ * @author Donal Fellows
+ */
+public interface Namespaces {
+	/**
+	 * The XLink specification's namespace name.
+	 */
+	public static final String XLINK = "http://www.w3.org/1999/xlink";
+	/**
+	 * The XML Digital Signature specification's namespace name.
+	 */
+	public static final String XSIG = "http://www.w3.org/2000/09/xmldsig#";
+	/**
+	 * The Usage Record specification's namespace name.
+	 */
+	public static final String UR = "http://schema.ogf.org/urf/2003/09/urf";
+	/**
+	 * The T2flow document format's namespace name.
+	 */
+	public static final String T2FLOW = "http://taverna.sf.net/2008/xml/t2flow";
+	/**
+	 * The namespace for the server.
+	 */
+	public static final String SERVER = "http://ns.taverna.org.uk/2010/xml/server/";
+	public static final String SERVER_REST = SERVER + "rest/";
+	public static final String SERVER_SOAP = SERVER + "soap/";
+	public static final String FEED = SERVER + "feed/";
+	public static final String ADMIN = SERVER + "admin/";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Permission.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Permission.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Permission.java
new file mode 100644
index 0000000..3e0a307
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Permission.java
@@ -0,0 +1,56 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Description of a permission to access a particular workflow run. Note that
+ * users always have full access to their own runs, as does any user with the "
+ * <tt>{@value org.taverna.server.master.common.Roles#ADMIN}</tt>" ability.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "Permission")
+@XmlEnum
+public enum Permission {
+	/** Indicates that a user cannot see the workflow run at all. */
+	@XmlEnumValue("none")
+	None,
+	/**
+	 * Indicates that a user can see the workflow run and its contents, but
+	 * can't modify anything.
+	 */
+	@XmlEnumValue("read")
+	Read,
+	/**
+	 * Indicates that a user can update most aspects of a workflow, but cannot
+	 * work with either its security features or its lifetime.
+	 */
+	@XmlEnumValue("update")
+	Update,
+	/**
+	 * Indicates that a user can update almost all aspects of a workflow, with
+	 * only its security features being shrouded.
+	 */
+	@XmlEnumValue("destroy")
+	Destroy
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/ProfileList.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/ProfileList.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/ProfileList.java
new file mode 100644
index 0000000..d9b0a9e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/ProfileList.java
@@ -0,0 +1,55 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+/**
+ * Description of the profiles that can apply to a workflow.
+ * 
+ * @author Donal K. Fellows
+ */
+@XmlRootElement(name = "profiles")
+@XmlType(name = "ProfileList")
+public class ProfileList {
+	public List<ProfileList.Info> profile = new ArrayList<ProfileList.Info>();
+
+	/**
+	 * Description of a single workflow profile.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "profile")
+	@XmlType(name = "Profile")
+	public static class Info {
+		@XmlValue
+		public String name;
+		/**
+		 * Whether this is the main profile.
+		 */
+		@XmlAttribute(name = "isMain")
+		public Boolean main;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Roles.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Roles.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Roles.java
new file mode 100644
index 0000000..bdcf876
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Roles.java
@@ -0,0 +1,38 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+/**
+ * The roles defined in this webapp.
+ * 
+ * @author Donal Fellows
+ */
+public interface Roles {
+	/** The role of a normal user. */
+	static final String USER = "ROLE_tavernauser";
+	/**
+	 * The role of an administrator. Administrators <i>should</i> have the
+	 * normal user role as well.
+	 */
+	static final String ADMIN = "ROLE_tavernasuperuser";
+	/**
+	 * The role of a workflow accessing itself. Do not give users this role.
+	 */
+	static final String SELF = "ROLE_tavernaworkflow";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/RunReference.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/RunReference.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/RunReference.java
new file mode 100644
index 0000000..cc80f60
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/RunReference.java
@@ -0,0 +1,80 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.master.common.VersionedElement.VERSION;
+
+import java.net.URI;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+/**
+ * A reference to a single workflow run, described using JAXB.
+ * 
+ * @author Donal Fellows
+ * @see org.taverna.server.master.interfaces.TavernaRun TavernaRun
+ */
+@XmlRootElement
+@XmlType(name = "TavernaRun")
+@XmlSeeAlso( { Workflow.class, DirEntryReference.class })
+public class RunReference {
+	/**
+	 * Where to get information about the run. For REST.
+	 */
+	@XmlAttribute(name = "href", namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI link;
+	/** What version of server produced this element? */
+	@XmlAttribute(namespace = SERVER)
+	public String serverVersion;
+	/**
+	 * The name of the run. For SOAP.
+	 */
+	@XmlValue
+	public String name;
+
+	/**
+	 * Make a blank run reference.
+	 */
+	public RunReference() {
+	}
+
+	/**
+	 * Make a reference to the given workflow run.
+	 * 
+	 * @param name
+	 *            The name of the run.
+	 * @param ub
+	 *            A factory for URIs, or <tt>null</tt> if none is to be made.
+	 */
+	public RunReference(String name, UriBuilder ub) {
+		this.serverVersion = VERSION;
+		this.name = name;
+		if (ub != null)
+			this.link = ub.build(name);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Status.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Status.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Status.java
new file mode 100644
index 0000000..1aad4ef
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Status.java
@@ -0,0 +1,57 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * States of a workflow run. They are {@link #Initialized Initialized},
+ * {@link #Operating Operating}, {@link #Stopped Stopped}, and {@link #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
+ */
+@XmlEnum
+@XmlType(name = "Status")
+public enum Status {
+	/**
+	 * The workflow run has been created, but is not yet running. The run will
+	 * need to be manually moved to {@link #Operating Operating} when ready.
+	 */
+	Initialized,
+	/**
+	 * The workflow run is going, reading input, generating output, etc. Will
+	 * eventually either move automatically to {@link #Finished Finished} or can
+	 * be moved manually to {@link #Stopped Stopped} (where supported).
+	 */
+	Operating,
+	/**
+	 * The workflow run is paused, and will need to be moved back to
+	 * {@link #Operating 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/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Trust.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Trust.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Trust.java
new file mode 100644
index 0000000..c61e72a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Trust.java
@@ -0,0 +1,92 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.io.Serializable;
+import java.security.cert.Certificate;
+import java.util.Collection;
+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.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * A description of a trusted identity or identities. This description is
+ * characterised by a file visible to the workflow run that contains one or more
+ * certificates.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "TrustDescriptor")
+@XmlRootElement(name = "trustedIdentity")
+@SuppressWarnings("serial")
+public final class Trust implements Serializable {
+	/** The location of this descriptor in the REST world. */
+	@XmlAttribute(namespace = XLINK)
+	public String href;
+	/**
+	 * The location of this descriptor in the SOAP world. Must match corrected
+	 * with the {@link #href} field.
+	 */
+	@XmlTransient
+	public String id;
+	/**
+	 * The file containing the certificate(s). This is resolved with respect to
+	 * the workflow run working directory.
+	 */
+	@XmlElement
+	public String certificateFile;
+	/**
+	 * The type of certificate file. Defaults to <tt>X.509</tt> if unspecified.
+	 */
+	@XmlElement
+	public String fileType;
+	/**
+	 * The encoded serialized keystore containing the certificate(s).
+	 */
+	@XmlElement
+	public byte[] certificateBytes;
+	/**
+	 * The names of the server(s) identified by this trust.
+	 */
+	@XmlElement
+	public List<String> serverName;
+	/**
+	 * The collection of certificates loaded from the specified file. This is
+	 * always <tt>null</tt> before validation.
+	 */
+	public transient Collection<? extends Certificate> loadedCertificates;
+
+	@Override
+	public int hashCode() {
+		return id.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o == null || !(o instanceof Trust))
+			return false;
+		return id.equals(((Trust) o).id);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Uri.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Uri.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Uri.java
new file mode 100644
index 0000000..ba0bb3c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/Uri.java
@@ -0,0 +1,445 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.Map;
+
+import javax.annotation.PreDestroy;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriBuilderException;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.web.PortMapper;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A class that makes it simpler to work with an element with a {@link URI} in
+ * an <tt>href</tt> attribute. Done with JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "Location")
+public class Uri {
+	static Log log = getLog("Taverna.Server.UriRewriter");
+	private static final String SECURE_SCHEME = "https";
+	/**
+	 * This type is characterised by an attribute that is the reference to some
+	 * other element.
+	 */
+	@XmlAttribute(name = "href", namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI ref;
+
+	/** Make a reference that points nowhere. */
+	public Uri() {
+	}
+
+	/**
+	 * Make a reference to the given location.
+	 * 
+	 * @param ref
+	 *            Where to point to.
+	 */
+	public Uri(@Nonnull URI ref) {
+		this.ref = secure(ref);
+	}
+
+	/**
+	 * Make a reference from the factory with the given parameters.
+	 * 
+	 * @param ub
+	 *            The configured factory.
+	 * @param strings
+	 *            The parameters to the factory.
+	 */
+	public Uri(@Nonnull UriBuilder ub, String... strings) {
+		ref = secure(ub).build((Object[]) strings);
+	}
+
+	/**
+	 * Make a reference from the factory with the given parameters.
+	 * 
+	 * @param ui
+	 *            The factory factory.
+	 * @param path
+	 *            The path to configure the factory with.
+	 * @param strings
+	 *            The parameters to the factory.
+	 */
+	public Uri(@Nonnull UriInfo ui, @Nonnull String path, String... strings) {
+		this(ui, true, path, strings);
+	}
+
+	/**
+	 * Make a reference from the factory with the given parameters.
+	 * 
+	 * @param ui
+	 *            The factory factory.
+	 * @param secure
+	 *            Whether the URI should be required to use HTTPS.
+	 * @param path
+	 *            The path to configure the factory with.
+	 * @param strings
+	 *            The parameters to the factory.
+	 */
+	public Uri(@Nonnull UriInfo ui, boolean secure, @Nonnull String path,
+			String... strings) {
+		UriBuilder ub = ui.getAbsolutePathBuilder();
+		if (secure) {
+			ub = secure(ub);
+		}
+		ref = ub.path(path).build((Object[]) strings);
+	}
+
+	public static UriBuilder secure(UriBuilder ub) {
+		return Rewriter.getInstance().getSecuredUriBuilder(ub);
+	}
+
+	public static UriBuilder secure(UriInfo ui) {
+		return secure(ui.getAbsolutePathBuilder());
+	}
+
+	public static URI secure(URI uri) {
+		URI newURI = secure(fromUri(uri)).build();
+		if (log.isDebugEnabled())
+			log.debug("rewrote " + uri + " to " + newURI);
+		return newURI;
+	}
+
+	public static URI secure(URI base, String uri) {
+		URI newURI = secure(fromUri(base.resolve(uri))).build();
+		if (log.isDebugEnabled())
+			log.debug("rewrote " + uri + " to " + newURI);
+		return newURI;
+	}
+
+	/**
+	 * A bean that allows configuration of how to rewrite generated URIs to be
+	 * secure.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public static class Rewriter {
+		private static Rewriter instance;
+		private PortMapper portMapper;
+		private boolean suppress;
+		private String rewriteRE = "://[^/]+/[^/]+";
+		private String rewriteTarget;
+
+		static Rewriter getInstance() {
+			if (instance == null)
+				new Rewriter();
+			return instance;
+		}
+
+		@Autowired
+		public void setPortMapper(PortMapper portMapper) {
+			this.portMapper = portMapper;
+		}
+
+		/**
+		 * Whether to suppress rewriting of URIs to be secure.
+		 * 
+		 * @param suppressSecurity
+		 *            True if no rewriting should be done.
+		 */
+		public void setSuppressSecurity(boolean suppressSecurity) {
+			suppress = suppressSecurity;
+		}
+
+		public void setRewriteRegexp(String rewriteRegexp) {
+			this.rewriteRE = rewriteRegexp;
+		}
+
+		/**
+		 * What to rewrite the host, port and web-app name to be.
+		 * 
+		 * @param rewriteTarget
+		 *            What to rewrite to, or "<tt>NONE</tt>" for no rewrite.
+		 */
+		public void setRewriteTarget(String rewriteTarget) {
+			if (rewriteTarget.isEmpty())
+				this.rewriteTarget = null;
+			else if (rewriteTarget.equals("NONE"))
+				this.rewriteTarget = null;
+			else if (rewriteTarget.startsWith("${"))
+				this.rewriteTarget = null;
+			else
+				this.rewriteTarget = "://" + rewriteTarget;
+		}
+
+		private Integer lookupHttpsPort(URI uri) {
+			if (portMapper != null)
+				return portMapper.lookupHttpsPort(uri.getPort());
+			return null;
+		}
+
+		public Rewriter() {
+			instance = this;
+		}
+
+		@PreDestroy
+		public void done() {
+			instance = null;
+			Uri.log = null;
+		}
+
+		@Nonnull
+		URI rewrite(@Nonnull String url) {
+			if (rewriteTarget != null)
+				url = url.replaceFirst(rewriteRE, rewriteTarget);
+			return URI.create(url);
+		}
+
+		@Nonnull
+		public UriBuilder getSecuredUriBuilder(@Nonnull UriBuilder uribuilder) {
+			if (suppress)
+				return uribuilder.clone();
+			UriBuilder ub = new RewritingUriBuilder(uribuilder);
+			Integer secPort = null;
+			try {
+				secPort = lookupHttpsPort(ub.build());
+			} catch (Exception e) {
+				/*
+				 * Do not log this; we know why it happens and don't actually
+				 * care to do anything about it. All it does is fill up the log
+				 * with pointless scariness!
+				 */
+
+				// log.debug("failed to extract current URI port", e);
+			}
+			if (secPort == null || secPort.intValue() == -1)
+				return ub.scheme(SECURE_SCHEME);
+			return ub.scheme(SECURE_SCHEME).port(secPort);
+		}
+
+		/**
+		 * {@link UriBuilder} that applies a rewrite rule to the URIs produced
+		 * by the wrapped builder.
+		 * 
+		 * @author Donal Fellows
+		 */
+		class RewritingUriBuilder extends UriBuilder {
+			private UriBuilder wrapped;
+
+			RewritingUriBuilder(UriBuilder builder) {
+				wrapped = builder.clone();
+			}
+
+			private URI rewrite(URI uri) {
+				return Rewriter.this.rewrite(uri.toString());
+			}
+
+			@Override
+			public UriBuilder clone() {
+				return new RewritingUriBuilder(wrapped);
+			}
+
+			@Override
+			public URI buildFromMap(Map<String, ?> values)
+					throws IllegalArgumentException, UriBuilderException {
+				return rewrite(wrapped.buildFromMap(values));
+			}
+
+			@Override
+			public URI buildFromEncodedMap(Map<String, ? extends Object> values)
+					throws IllegalArgumentException, UriBuilderException {
+				return rewrite(wrapped.buildFromEncodedMap(values));
+			}
+
+			@Override
+			public URI build(Object... values) throws IllegalArgumentException,
+					UriBuilderException {
+				return rewrite(wrapped.build(values));
+			}
+
+			@Override
+			public URI build(Object[] values, boolean encodeSlashInPath)
+					throws IllegalArgumentException, UriBuilderException {
+				return rewrite(wrapped.build(values, encodeSlashInPath));
+			}
+
+			@Override
+			public URI buildFromEncoded(Object... values)
+					throws IllegalArgumentException, UriBuilderException {
+				return rewrite(wrapped.buildFromEncoded(values));
+			}
+
+			@Override
+			public URI buildFromMap(Map<String, ?> values,
+					boolean encodeSlashInPath) throws IllegalArgumentException,
+					UriBuilderException {
+				return rewrite(wrapped.buildFromEncoded(values,
+						encodeSlashInPath));
+			}
+
+			@Override
+			public UriBuilder uri(URI uri) throws IllegalArgumentException {
+				wrapped.uri(uri);
+				return this;
+			}
+
+			@Override
+			public UriBuilder uri(String uriTemplate)
+					throws IllegalArgumentException {
+				wrapped.uri(uriTemplate);
+				return this;
+			}
+
+			@Override
+			public String toTemplate() {
+				return wrapped.toTemplate();
+			}
+
+			@Override
+			public UriBuilder scheme(String scheme)
+					throws IllegalArgumentException {
+				wrapped.scheme(scheme);
+				return this;
+			}
+
+			@Override
+			public UriBuilder schemeSpecificPart(String ssp)
+					throws IllegalArgumentException {
+				wrapped.schemeSpecificPart(ssp);
+				return this;
+			}
+
+			@Override
+			public UriBuilder userInfo(String ui) {
+				wrapped.userInfo(ui);
+				return this;
+			}
+
+			@Override
+			public UriBuilder host(String host) throws IllegalArgumentException {
+				wrapped.host(host);
+				return this;
+			}
+
+			@Override
+			public UriBuilder port(int port) throws IllegalArgumentException {
+				wrapped.port(port);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replacePath(String path) {
+				wrapped.replacePath(path);
+				return this;
+			}
+
+			@Override
+			public UriBuilder path(String path) throws IllegalArgumentException {
+				wrapped.path(path);
+				return this;
+			}
+
+			@Override
+			public UriBuilder path(
+					@java.lang.SuppressWarnings("rawtypes") Class resource)
+					throws IllegalArgumentException {
+				wrapped.path(resource);
+				return this;
+			}
+
+			@Override
+			public UriBuilder path(
+					@java.lang.SuppressWarnings("rawtypes") Class resource,
+					String method) throws IllegalArgumentException {
+				wrapped.path(resource, method);
+				return this;
+			}
+
+			@Override
+			public UriBuilder path(Method method)
+					throws IllegalArgumentException {
+				wrapped.path(method);
+				return this;
+			}
+
+			@Override
+			public UriBuilder segment(String... segments)
+					throws IllegalArgumentException {
+				wrapped.segment(segments);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replaceMatrix(String matrix)
+					throws IllegalArgumentException {
+				wrapped.replaceMatrix(matrix);
+				return this;
+			}
+
+			@Override
+			public UriBuilder matrixParam(String name, Object... values)
+					throws IllegalArgumentException {
+				wrapped.matrixParam(name, values);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replaceMatrixParam(String name, Object... values)
+					throws IllegalArgumentException {
+				wrapped.replaceMatrixParam(name, values);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replaceQuery(String query)
+					throws IllegalArgumentException {
+				wrapped.replaceQuery(query);
+				return this;
+			}
+
+			@Override
+			public UriBuilder queryParam(String name, Object... values)
+					throws IllegalArgumentException {
+				wrapped.queryParam(name, values);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replaceQueryParam(String name, Object... values)
+					throws IllegalArgumentException {
+				wrapped.replaceQueryParam(name, values);
+				return this;
+			}
+
+			@Override
+			public UriBuilder fragment(String fragment) {
+				wrapped.fragment(fragment);
+				return this;
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/VersionedElement.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/VersionedElement.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/VersionedElement.java
new file mode 100644
index 0000000..735a72d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/common/VersionedElement.java
@@ -0,0 +1,78 @@
+/*
+ */
+package org.taverna.server.master.common;
+/*
+ * 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.
+ */
+
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * The type of an element that declares the version of the server that produced
+ * it.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "VersionedElement", namespace = SERVER)
+public abstract class VersionedElement {
+	/** What version of server produced this element? */
+	@XmlAttribute(namespace = SERVER)
+	public String serverVersion;
+	/** What revision of server produced this element? Derived from SCM commit. */
+	@XmlAttribute(namespace = SERVER)
+	public String serverRevision;
+	/** When was the server built? */
+	@XmlAttribute(namespace = SERVER)
+	public String serverBuildTimestamp;
+	public static final String VERSION, REVISION, TIMESTAMP;
+	static {
+		Log log = getLog("Taverna.Server.Webapp");
+		Properties p = new Properties();
+		try {
+			try (InputStream is = VersionedElement.class
+					.getResourceAsStream("/version.properties")) {
+				p.load(is);
+			}
+		} catch (IOException e) {
+			log.warn("failed to read /version.properties", e);
+		}
+		VERSION = p.getProperty("tavernaserver.version", "unknownVersion");
+		REVISION = String.format("%s (tag: %s)",
+				p.getProperty("tavernaserver.branch", "unknownRevision"),
+				p.getProperty("tavernaserver.revision.describe", "unknownTag"));
+		TIMESTAMP = p
+				.getProperty("tavernaserver.timestamp", "unknownTimestamp");
+	}
+
+	public VersionedElement() {
+	}
+
+	protected VersionedElement(boolean ignored) {
+		serverVersion = VERSION;
+		serverRevision = REVISION;
+		serverBuildTimestamp = TIMESTAMP;
+	}
+}


[24/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/IllegalArgumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/IllegalArgumentHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/IllegalArgumentHandler.java
new file mode 100644
index 0000000..d7ec8f4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/IllegalArgumentHandler.java
@@ -0,0 +1,34 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.UNSUPPORTED_MEDIA_TYPE;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+public class IllegalArgumentHandler extends HandlerCore implements
+		ExceptionMapper<IllegalArgumentException> {
+	@Override
+	public Response toResponse(IllegalArgumentException exn) {
+		return respond(UNSUPPORTED_MEDIA_TYPE, exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ImplementationProblemHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ImplementationProblemHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ImplementationProblemHandler.java
new file mode 100644
index 0000000..806fc67
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ImplementationProblemHandler.java
@@ -0,0 +1,34 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.taverna.server.localworker.remote.ImplementationException;
+
+public class ImplementationProblemHandler extends HandlerCore implements
+		ExceptionMapper<ImplementationException> {
+	@Override
+	public Response toResponse(ImplementationException exception) {
+		return respond(INTERNAL_SERVER_ERROR, exception);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InputStreamMessageHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InputStreamMessageHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InputStreamMessageHandler.java
new file mode 100644
index 0000000..6b4470b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InputStreamMessageHandler.java
@@ -0,0 +1,120 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static java.lang.Long.parseLong;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Maps a stream from a client into a bounded ordinary input stream that the
+ * webapp can work with more easily.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+@Consumes(APPLICATION_OCTET_STREAM)
+public class InputStreamMessageHandler implements
+		MessageBodyReader<InputStream> {
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return InputStream.class.isAssignableFrom(type);
+	}
+
+	@Override
+	public InputStream readFrom(Class<InputStream> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		return new TransferStream(entityStream,
+				httpHeaders.get("Content-Length"));
+	}
+}
+
+/**
+ * The actual transfer thunk.
+ * 
+ * @author Donal Fellows
+ */
+class TransferStream extends InputStream {
+	private Log log = getLog("Taverna.Server.Handlers");
+
+	public TransferStream(InputStream entityStream, List<String> contentLength) {
+		this.entityStream = new BufferedInputStream(entityStream);
+		if (contentLength != null && contentLength.size() > 0) {
+			this.limit = parseLong(contentLength.get(0));
+			if (log.isDebugEnabled())
+				log.debug("will attempt to transfer " + this.limit + " bytes");
+		} else {
+			this.limit = -1;
+			if (log.isDebugEnabled())
+				log.debug("will attempt to transfer until EOF");
+		}
+	}
+
+	InputStream entityStream;
+	long limit;
+	long doneBytes = 0;
+
+	@Override
+	public int read() throws IOException {
+		if (limit >= 0 && doneBytes >= limit)
+			return -1;
+		int result = entityStream.read();
+		if (result >= 0)
+			doneBytes++;
+		return result;
+	}
+
+	@Override
+	public int read(byte[] ary, int off, int len) throws IOException {
+		if (limit >= 0) {
+			if (doneBytes >= limit)
+				return -1;
+			if (doneBytes + len > limit)
+				len = (int) (limit - doneBytes);
+		}
+		int readBytes = entityStream.read(ary, off, len);
+		if (readBytes >= 0)
+			doneBytes += readBytes;
+		return readBytes;
+	}
+
+	@Override
+	public void close() throws IOException {
+		entityStream.close();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InvalidCredentialHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InvalidCredentialHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InvalidCredentialHandler.java
new file mode 100644
index 0000000..7208aa4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/InvalidCredentialHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+
+@Provider
+public class InvalidCredentialHandler extends HandlerCore implements
+		ExceptionMapper<InvalidCredentialException> {
+	@Override
+	public Response toResponse(InvalidCredentialException exn) {
+		return respond(BAD_REQUEST, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/JAXBExceptionHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/JAXBExceptionHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/JAXBExceptionHandler.java
new file mode 100644
index 0000000..cf5952e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/JAXBExceptionHandler.java
@@ -0,0 +1,35 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import javax.xml.bind.JAXBException;
+
+@Provider
+public class JAXBExceptionHandler extends HandlerCore implements
+		ExceptionMapper<JAXBException> {
+	@Override
+	public Response toResponse(JAXBException exn) {
+		return respond(BAD_REQUEST, "APIEpicFail: " + exn.getErrorCode(), exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NegotiationFailedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NegotiationFailedHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NegotiationFailedHandler.java
new file mode 100644
index 0000000..00457fe
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NegotiationFailedHandler.java
@@ -0,0 +1,38 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static javax.ws.rs.core.Response.notAcceptable;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.rest.TavernaServerDirectoryREST.NegotiationFailedException;
+
+@Provider
+public class NegotiationFailedHandler implements
+		ExceptionMapper<NegotiationFailedException> {
+	@Override
+	public Response toResponse(NegotiationFailedException exn) {
+		return notAcceptable(exn.accepted).type(TEXT_PLAIN)
+				.entity(exn.getMessage()).build();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCreateHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCreateHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCreateHandler.java
new file mode 100644
index 0000000..f20f876
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCreateHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoCreateException;
+
+@Provider
+public class NoCreateHandler extends HandlerCore implements
+		ExceptionMapper<NoCreateException> {
+	@Override
+	public Response toResponse(NoCreateException exn) {
+		return respond(SERVICE_UNAVAILABLE, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCredentialHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCredentialHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCredentialHandler.java
new file mode 100644
index 0000000..6644901
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoCredentialHandler.java
@@ -0,0 +1,34 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.taverna.server.master.exceptions.NoCredentialException;
+
+public class NoCredentialHandler extends HandlerCore implements
+		ExceptionMapper<NoCredentialException> {
+	@Override
+	public Response toResponse(NoCredentialException exn) {
+		return respond(NOT_FOUND, exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDestroyHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDestroyHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDestroyHandler.java
new file mode 100644
index 0000000..2c0f5a9
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDestroyHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoDestroyException;
+
+@Provider
+public class NoDestroyHandler extends HandlerCore implements
+		ExceptionMapper<NoDestroyException> {
+	@Override
+	public Response toResponse(NoDestroyException exn) {
+		return respond(FORBIDDEN, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
new file mode 100644
index 0000000..2f72487
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+
+@Provider
+public class NoDirectoryEntryHandler extends HandlerCore implements
+		ExceptionMapper<NoDirectoryEntryException> {
+	@Override
+	public Response toResponse(NoDirectoryEntryException exn) {
+		return respond(NOT_FOUND, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoListenerHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoListenerHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoListenerHandler.java
new file mode 100644
index 0000000..e119b60
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoListenerHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoListenerException;
+
+@Provider
+public class NoListenerHandler extends HandlerCore implements
+		ExceptionMapper<NoListenerException> {
+	@Override
+	public Response toResponse(NoListenerException exn) {
+		return respond(BAD_REQUEST, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoUpdateHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoUpdateHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoUpdateHandler.java
new file mode 100644
index 0000000..2d5dde3
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NoUpdateHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoUpdateException;
+
+@Provider
+public class NoUpdateHandler extends HandlerCore implements
+		ExceptionMapper<NoUpdateException> {
+	@Override
+	public Response toResponse(NoUpdateException exn) {
+		return respond(FORBIDDEN, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NotOwnerHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NotOwnerHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NotOwnerHandler.java
new file mode 100644
index 0000000..baeb6aa
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/NotOwnerHandler.java
@@ -0,0 +1,34 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.taverna.server.master.exceptions.NotOwnerException;
+
+public class NotOwnerHandler extends HandlerCore implements
+		ExceptionMapper<NotOwnerException> {
+	@Override
+	public Response toResponse(NotOwnerException exn) {
+		return respond(FORBIDDEN, exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/OverloadedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/OverloadedHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/OverloadedHandler.java
new file mode 100644
index 0000000..9e142f3
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/OverloadedHandler.java
@@ -0,0 +1,35 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.OverloadedException;
+
+@Provider
+public class OverloadedHandler extends HandlerCore implements
+		ExceptionMapper<OverloadedException> {
+	@Override
+	public Response toResponse(OverloadedException exn) {
+		return respond(SERVICE_UNAVAILABLE, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/PermissionHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/PermissionHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/PermissionHandler.java
new file mode 100644
index 0000000..d7a4afc
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/PermissionHandler.java
@@ -0,0 +1,87 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.taverna.server.master.common.Permission;
+
+/**
+ * Handler that allows CXF to send and receive {@linkplain Permission
+ * permissions} as plain text directly.
+ * 
+ * @author Donal Fellows
+ */
+public class PermissionHandler implements MessageBodyReader<Permission>,
+		MessageBodyWriter<Permission> {
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return type.isAssignableFrom(Permission.class)
+				&& mediaType.isCompatible(TEXT_PLAIN_TYPE);
+	}
+
+	@Override
+	public long getSize(Permission t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return t.toString().length();
+	}
+
+	@Override
+	public void writeTo(Permission t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		new OutputStreamWriter(entityStream).write(t.toString());
+	}
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return type.isAssignableFrom(Permission.class)
+				&& mediaType.isCompatible(TEXT_PLAIN_TYPE);
+	}
+
+	@Override
+	public Permission readFrom(Class<Permission> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		char[] cbuf = new char[7];
+		int len = new InputStreamReader(entityStream).read(cbuf);
+		if (len < 0)
+			throw new IllegalArgumentException("no entity supplied");
+		return Permission.valueOf(new String(cbuf, 0, len));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/Scufl2DocumentHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
new file mode 100644
index 0000000..cf1ccdf
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
@@ -0,0 +1,100 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.common.Workflow;
+
+import org.apache.taverna.scufl2.api.io.ReaderException;
+import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
+import org.apache.taverna.scufl2.api.io.WriterException;
+
+/**
+ * Handler that allows a .scufl2 document to be read from and written to a REST
+ * message directly.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+public class Scufl2DocumentHandler implements MessageBodyReader<Workflow>,
+		MessageBodyWriter<Workflow> {
+	private static final MediaType SCUFL2_TYPE = new MediaType("application",
+			"vnd.taverna.scufl2.workflow-bundle");
+	public static final String SCUFL2 = "application/vnd.taverna.scufl2.workflow-bundle";
+	private WorkflowBundleIO io = new WorkflowBundleIO();
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (type.isAssignableFrom(Workflow.class))
+			return mediaType.isCompatible(SCUFL2_TYPE);
+		return false;
+	}
+
+	@Override
+	public Workflow readFrom(Class<Workflow> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		try {
+			return new Workflow(io.readBundle(entityStream, SCUFL2));
+		} catch (ReaderException e) {
+			throw new WebApplicationException(e, 403);
+		}
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (Workflow.class.isAssignableFrom(type))
+			return mediaType.isCompatible(SCUFL2_TYPE);
+		return false;
+	}
+
+	@Override
+	public long getSize(Workflow workflow, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(Workflow workflow, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		try {
+			io.writeBundle(workflow.getScufl2Workflow(), entityStream, SCUFL2);
+		} catch (WriterException e) {
+			throw new WebApplicationException(e);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/T2FlowDocumentHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
new file mode 100644
index 0000000..1f6d328
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
@@ -0,0 +1,131 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.taverna.server.master.common.Workflow;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+/**
+ * Handler that allows a .t2flow document to be read from and written to a REST
+ * message directly.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+public class T2FlowDocumentHandler implements MessageBodyReader<Workflow>,
+		MessageBodyWriter<Workflow> {
+	private static final MediaType T2FLOW_TYPE = new MediaType("application",
+			"vnd.taverna.t2flow+xml");
+	public static final String T2FLOW = "application/vnd.taverna.t2flow+xml";
+	public static final String T2FLOW_ROOTNAME = "workflow";
+	public static final String T2FLOW_NS = "http://taverna.sf.net/2008/xml/t2flow";
+	private DocumentBuilderFactory db;
+	private TransformerFactory transformer;
+
+	public T2FlowDocumentHandler() throws ParserConfigurationException,
+			TransformerConfigurationException {
+		db = DocumentBuilderFactory.newInstance();
+		db.setNamespaceAware(true);
+		transformer = TransformerFactory.newInstance();
+	}
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (type.isAssignableFrom(Workflow.class))
+			return mediaType.isCompatible(T2FLOW_TYPE);
+		return false;
+	}
+
+	@Override
+	public Workflow readFrom(Class<Workflow> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		Document doc;
+		try {
+			doc = db.newDocumentBuilder().parse(entityStream);
+		} catch (SAXException e) {
+			throw new WebApplicationException(e, 403);
+		} catch (ParserConfigurationException e) {
+			throw new WebApplicationException(e);
+		}
+		Workflow workflow = new Workflow(doc.getDocumentElement());
+		if (doc.getDocumentElement().getNamespaceURI().equals(T2FLOW_NS)
+				&& doc.getDocumentElement().getNodeName()
+						.equals(T2FLOW_ROOTNAME))
+			return workflow;
+		throw new WebApplicationException(Response.status(403)
+				.entity("invalid T2flow document; bad root element")
+				.type("text/plain").build());
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (Workflow.class.isAssignableFrom(type))
+			return mediaType.isCompatible(T2FLOW_TYPE);
+		return false;
+	}
+
+	@Override
+	public long getSize(Workflow workflow, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(Workflow workflow, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		try {
+			transformer.newTransformer().transform(
+					new DOMSource(workflow.getT2flowWorkflow()),
+					new StreamResult(entityStream));
+		} catch (TransformerException e) {
+			if (e.getCause() != null && e.getCause() instanceof IOException)
+				throw (IOException) e.getCause();
+			throw new WebApplicationException(e);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/URIListHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/URIListHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/URIListHandler.java
new file mode 100644
index 0000000..453ac73
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/URIListHandler.java
@@ -0,0 +1,134 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.status;
+import static org.taverna.server.master.rest.handler.URIListHandler.URI_LIST;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+/**
+ * Deserialization and serialization engine for the <tt>{@value #URI_LIST}</tt>
+ * content type.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+@Consumes(URI_LIST)
+public class URIListHandler implements MessageBodyReader<List<URI>>,
+		MessageBodyWriter<List<URI>> {
+	/** The content type we handle. */
+	public static final String URI_LIST = "text/uri-list";
+	private static final MediaType URILIST = new MediaType("text", "uri-list");
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return type.isAssignableFrom(ArrayList.class)
+				&& genericType instanceof ParameterizedType
+				&& ((Class<?>) ((ParameterizedType) genericType)
+						.getActualTypeArguments()[0])
+						.isAssignableFrom(URI.class)
+				&& URILIST.isCompatible(mediaType);
+	}
+
+	@Override
+	public List<URI> readFrom(Class<List<URI>> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		String enc = mediaType.getParameters().get("encoding");
+		Charset c = (enc == null) ? Charset.defaultCharset() : Charset
+				.forName(enc);
+		BufferedReader br = new BufferedReader(new InputStreamReader(
+				entityStream, c));
+		ArrayList<URI> uris = new ArrayList<>();
+		String line;
+		while ((line = br.readLine()) != null) {
+			if (line.startsWith("#"))
+				continue;
+			try {
+				uris.add(new URI(line));
+			} catch (URISyntaxException e) {
+				throw new WebApplicationException(e, status(422).entity(
+						"ill-formed URI").build());
+			}
+		}
+		return uris;
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return List.class.isAssignableFrom(type)
+				&& genericType instanceof ParameterizedType
+				&& ((ParameterizedType) genericType).getActualTypeArguments()[0] == URI.class
+				&& URILIST.isCompatible(mediaType);
+	}
+
+	@Override
+	public long getSize(List<URI> list, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	private static final String PREFERRED_ENCODING = "UTF-8";
+
+	@Override
+	public void writeTo(List<URI> list, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException {
+		String encoding = mediaType.getParameters().get("encoding");
+		if (encoding == null) {
+			encoding = PREFERRED_ENCODING;
+			httpHeaders.putSingle("Content-Type", URI_LIST + ";encoding="
+					+ encoding);
+		}
+		BufferedWriter w = new BufferedWriter(new OutputStreamWriter(
+				entityStream, encoding));
+		for (URI uri : list) {
+			w.write(uri.toString());
+			w.newLine();
+		}
+		w.flush();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/UnknownRunHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/UnknownRunHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/UnknownRunHandler.java
new file mode 100644
index 0000000..4d5c6e8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/UnknownRunHandler.java
@@ -0,0 +1,36 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.UnknownRunException;
+
+@Provider
+public class UnknownRunHandler extends HandlerCore implements
+		ExceptionMapper<UnknownRunException> {
+	@Override
+	public Response toResponse(UnknownRunException exn) {
+		return respond(NOT_FOUND, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ZipStreamHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ZipStreamHandler.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ZipStreamHandler.java
new file mode 100644
index 0000000..69e526d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/ZipStreamHandler.java
@@ -0,0 +1,67 @@
+/*
+ */
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static org.apache.commons.io.IOUtils.copy;
+import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.interfaces.Directory.ZipStream;
+
+/**
+ * How to write a ZIP file as the result entity of a request.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+@Produces("application/zip")
+public class ZipStreamHandler implements MessageBodyWriter<ZipStream> {
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return ZipStream.class.isAssignableFrom(type)
+				&& mediaType.equals(APPLICATION_ZIP_TYPE);
+	}
+
+	@Override
+	public long getSize(ZipStream t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(ZipStream zipStream, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		copy(zipStream, entityStream);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/package-info.java
new file mode 100644
index 0000000..8404ead
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/handler/package-info.java
@@ -0,0 +1,44 @@
+/*
+ */
+/**
+ * This package contains type handlers for the RESTful interface to Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER_REST, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "port", namespaceURI = DATA),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.rest.handler;
+/*
+ * 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.
+ */
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.port_description.Namespaces.DATA;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/package-info.java
new file mode 100644
index 0000000..d35dc7b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/package-info.java
@@ -0,0 +1,44 @@
+/*
+ */
+/**
+ * This package contains the RESTful interface to Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER_REST, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "port", namespaceURI = DATA),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.port_description.Namespaces.DATA;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/DirEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/DirEntry.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/DirEntry.java
new file mode 100644
index 0000000..752c6b1
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/DirEntry.java
@@ -0,0 +1,113 @@
+/*
+ */
+package org.taverna.server.master.soap;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.net.URI;
+
+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.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.common.DirEntryReference;
+
+/**
+ * A more Taverna-friendly version of the directory entry descriptor classes.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "DirectoryEntry")
+@XmlRootElement(name = "entry")
+@XmlSeeAlso({ DirEntry.File.class, DirEntry.Directory.class })
+public class DirEntry {
+	/** A link to the entry. Ignored on input. */
+	@XmlAttribute(name = "href", namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI link;
+	@XmlAttribute
+	public String name;
+	@XmlElement(required = true)
+	public String path;
+
+	/**
+	 * A file in a directory.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlType(name = "FileDirEntry")
+	@XmlRootElement(name = "file")
+	public static class File extends DirEntry {
+	}
+
+	/**
+	 * A directory in a directory. That is, a sub-directory.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlType(name = "DirectoryDirEntry")
+	@XmlRootElement(name = "dir")
+	public static class Directory extends DirEntry {
+	}
+
+	/**
+	 * Converts from the "common" format to the subclasses of this class.
+	 * 
+	 * @param deref
+	 *            The "common" format handle to convert.
+	 * @return The converted handle
+	 */
+	public static DirEntry convert(DirEntryReference deref) {
+		DirEntry result;
+		if (deref instanceof DirEntryReference.DirectoryReference)
+			result = new Directory();
+		else if (deref instanceof DirEntryReference.FileReference)
+			result = new File();
+		else
+			result = new DirEntry();
+		result.link = deref.link;
+		result.name = deref.name;
+		result.path = deref.path;
+		return result;
+	}
+
+	/**
+	 * Converts to the "common" format from the subclasses of this class.
+	 * 
+	 * @param deref
+	 *            The subclass of this class to convert.
+	 * @return The converted reference.
+	 */
+	public static DirEntryReference convert(DirEntry de) {
+		DirEntryReference result;
+		if (de instanceof Directory)
+			result = new DirEntryReference.DirectoryReference();
+		else if (de instanceof File)
+			result = new DirEntryReference.FileReference();
+		else
+			result = new DirEntryReference();
+		result.link = de.link;
+		result.name = de.name;
+		result.path = de.path;
+		return result;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/FileContents.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/FileContents.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/FileContents.java
new file mode 100644
index 0000000..fa9978b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/FileContents.java
@@ -0,0 +1,184 @@
+/*
+ */
+package org.taverna.server.master.soap;
+/*
+ * 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.
+ */
+
+import static java.lang.Math.min;
+import static java.lang.System.arraycopy;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlMimeType;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * An MTOM-capable description of how to transfer the contents of a file.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "FileContents")
+public class FileContents {
+	@XmlElement
+	public String name;
+	@XmlMimeType("application/octet-stream") // JAXB bug: must be this
+	public DataHandler fileData;
+
+	/**
+	 * Initialize the contents of this descriptor from the given file and
+	 * content type.
+	 * 
+	 * @param file
+	 *            The file that is to be reported.
+	 * @param contentType
+	 *            The estimated content type of the file.
+	 */
+	public void setFile(File file, String contentType) {
+		name = file.getFullName();
+		fileData = new DataHandler(new TavernaFileSource(file, contentType));
+	}
+
+	/**
+	 * Write the content described by this class to the specified file.
+	 * @param file The file to write to; must already exist.
+	 * @throws IOException
+	 * @throws FilesystemAccessException
+	 */
+	public void writeToFile(File file) throws IOException,
+			FilesystemAccessException {
+		try (InputStream is = fileData.getInputStream()) {
+			byte[] buf = new byte[65536];
+			file.setContents(new byte[0]);
+			while (true) {
+				int len = is.read(buf);
+				if (len <= 0)
+					return;
+				if (len == buf.length)
+					file.appendContents(buf);
+				else {
+					byte[] shortbuf = new byte[len];
+					arraycopy(buf, 0, shortbuf, 0, len);
+					file.appendContents(shortbuf);
+				}
+			}
+		}
+	}
+}
+
+/**
+ * A data source that knows how to communicate with the Taverna Server back-end.
+ * 
+ * @author Donal Fellows
+ */
+class TavernaFileSource implements DataSource {
+	TavernaFileSource(File f, String type) {
+		this.f = f;
+		this.type = type;
+	}
+
+	private final File f;
+	private final String type;
+
+	@Override
+	public String getContentType() {
+		return type;
+	}
+
+	@Override
+	public String getName() {
+		return f.getName();
+	}
+
+	@Override
+	public InputStream getInputStream() throws IOException {
+		final File f = this.f;
+		return new InputStream() {
+			private int idx;
+
+			@Override
+			public int read(byte[] b, int off, int len) throws IOException {
+				byte[] r;
+				try {
+					r = f.getContents(idx, len);
+				} catch (FilesystemAccessException e) {
+					throw new IOException(e);
+				}
+				if (r == null)
+					return -1;
+				len = min(len, r.length);
+				arraycopy(r, 0, b, off, len);
+				idx += len;
+				return len;
+			}
+
+			@Override
+			public int read() throws IOException {
+				byte[] r;
+				try {
+					r = f.getContents(idx, 1);
+				} catch (FilesystemAccessException e) {
+					throw new IOException(e);
+				}
+				if (r == null)
+					return -1;
+				idx++;
+				return r[0];
+			}
+		};
+	}
+
+	@Override
+	public OutputStream getOutputStream() throws IOException {
+		final File f = this.f;
+		return new OutputStream() {
+			private boolean append = false;
+
+			@Override
+			public void write(int b) throws IOException {
+				write(new byte[] { (byte) b });
+			}
+
+			@Override
+			public void write(byte[] b) throws IOException {
+				try {
+					if (append)
+						f.appendContents(b);
+					else
+						f.setContents(b);
+					append = true;
+				} catch (FilesystemAccessException e) {
+					throw new IOException(e);
+				}
+			}
+
+			@Override
+			public void write(byte[] b, int off, int len) throws IOException {
+				byte[] ary = new byte[len];
+				arraycopy(b, off, ary, 0, len);
+				write(ary);
+			}
+		};
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/PermissionList.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/PermissionList.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/PermissionList.java
new file mode 100644
index 0000000..6568ab2
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/soap/PermissionList.java
@@ -0,0 +1,63 @@
+/*
+ */
+package org.taverna.server.master.soap;
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.common.Permission;
+
+/**
+ * The list of permissions to access a workflow run of users <i>other than the
+ * owner</i>. This class exists to support the JAXB mapping.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "PermissionList")
+@XmlRootElement(name = "permissionList")
+public class PermissionList {
+	/**
+	 * The type of a single mapped permission. This class exists to support the
+	 * JAXB mapping.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlType(name = "")
+	public static class SinglePermissionMapping {
+		public SinglePermissionMapping() {
+		}
+
+		public SinglePermissionMapping(String user, Permission permission) {
+			this.userName = user;
+			this.permission = permission;
+		}
+
+		/** The name of the user that this talks about. */
+		public String userName;
+		/** The permission level that the user is granted. */
+		public Permission permission;
+	}
+
+	/** The list of (non-default) permissions granted. */
+	@XmlElement
+	public List<SinglePermissionMapping> permission;
+}
\ No newline at end of file


[27/42] incubator-taverna-server git commit: package org.taverna -> org.apache.taverna

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerState.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerState.java
new file mode 100644
index 0000000..e32dcca
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/LocalWorkerState.java
@@ -0,0 +1,475 @@
+/*
+ */
+package org.taverna.server.master.localworker;
+/*
+ * 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.
+ */
+
+import static java.io.File.separator;
+import static java.lang.System.getProperty;
+import static java.rmi.registry.Registry.REGISTRY_PORT;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableList;
+import static org.taverna.server.master.defaults.Default.EXTRA_ARGUMENTS;
+import static org.taverna.server.master.defaults.Default.PASSWORD_FILE;
+import static org.taverna.server.master.defaults.Default.REGISTRY_JAR;
+import static org.taverna.server.master.defaults.Default.RMI_PREFIX;
+import static org.taverna.server.master.defaults.Default.RUN_LIFE_MINUTES;
+import static org.taverna.server.master.defaults.Default.RUN_OPERATING_LIMIT;
+import static org.taverna.server.master.defaults.Default.SECURE_FORK_IMPLEMENTATION_JAR;
+import static org.taverna.server.master.defaults.Default.SERVER_WORKER_IMPLEMENTATION_JAR;
+import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_POLL_SLEEP;
+import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_WAIT;
+import static org.taverna.server.master.localworker.PersistedState.KEY;
+import static org.taverna.server.master.localworker.PersistedState.makeInstance;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.net.URI;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.jdo.annotations.PersistenceAware;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.defaults.Default;
+import org.taverna.server.master.utils.JDOSupport;
+import org.taverna.server.master.worker.WorkerModel;
+
+/**
+ * The persistent state of a local worker factory.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceAware
+public class LocalWorkerState extends JDOSupport<PersistedState> implements
+		WorkerModel {	
+	public LocalWorkerState() {
+		super(PersistedState.class);
+	}
+
+	private LocalWorkerState self;
+
+	@Required
+	public void setSelf(LocalWorkerState self) {
+		this.self = self;
+	}
+
+	/** Initial lifetime of runs, in minutes. */
+	int defaultLifetime;
+	/**
+	 * Maximum number of runs to exist at once. Note that this includes when
+	 * they are just existing for the purposes of file transfer (
+	 * {@link Status#Initialized}/{@link Status#Finished} states).
+	 */
+	int maxRuns;
+	/**
+	 * Prefix to use for RMI names.
+	 */
+	String factoryProcessNamePrefix;
+	/**
+	 * Full path name of the script used to start running a workflow; normally
+	 * expected to be "<i>somewhere/</i><tt>executeWorkflow.sh</tt>".
+	 */
+	String executeWorkflowScript;
+	/** Default value for {@link #executeWorkflowScript}. */
+	private transient String defaultExecuteWorkflowScript;
+	/**
+	 * Full path name of the file containing the password used to launch workers
+	 * as other users. The file is normally expected to contain a single line,
+	 * the password, and to be thoroughly locked down so only the user running
+	 * the server (e.g., "<tt>tomcat</tt>") can read it; it will probably reside
+	 * in either the user's home directory or in a system configuration
+	 * directory.
+	 */
+	String passwordFile;
+	/** Default value for {@link #passwordFile}. */
+	private transient String defaultPasswordFile = PASSWORD_FILE;
+	/**
+	 * The extra arguments to pass to the subprocess.
+	 */
+	String[] extraArgs;
+	/**
+	 * How long to wait for subprocess startup, in seconds.
+	 */
+	int waitSeconds;
+	/**
+	 * Polling interval to use during startup, in milliseconds.
+	 */
+	int sleepMS;
+	/**
+	 * Full path name to the worker process's implementation JAR.
+	 */
+	String serverWorkerJar;
+	private static final String DEFAULT_WORKER_JAR = LocalWorkerState.class
+			.getClassLoader().getResource(SERVER_WORKER_IMPLEMENTATION_JAR)
+			.getFile();
+	/**
+	 * Full path name to the Java binary to use to run the subprocess.
+	 */
+	String javaBinary;
+	private static final String DEFAULT_JAVA_BINARY = getProperty("java.home")
+			+ separator + "bin" + separator + "java";
+	/**
+	 * Full path name to the secure fork process's implementation JAR.
+	 */
+	String serverForkerJar;
+	private static final String DEFAULT_FORKER_JAR = LocalWorkerState.class
+			.getClassLoader().getResource(SECURE_FORK_IMPLEMENTATION_JAR)
+			.getFile();
+
+	String registryHost;
+	int registryPort;
+
+	int operatingLimit;
+
+	URI[] permittedWorkflows;
+	private String registryJar;
+	private static final String DEFAULT_REGISTRY_JAR = LocalWorkerState.class
+			.getClassLoader().getResource(REGISTRY_JAR).getFile();
+
+	@Override
+	public void setDefaultLifetime(int defaultLifetime) {
+		this.defaultLifetime = defaultLifetime;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getDefaultLifetime() {
+		return defaultLifetime < 1 ? RUN_LIFE_MINUTES : defaultLifetime;
+	}
+
+	@Override
+	public void setMaxRuns(int maxRuns) {
+		this.maxRuns = maxRuns;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getMaxRuns() {
+		return maxRuns < 1 ? Default.RUN_COUNT_MAX : maxRuns;
+	}
+
+	@Override
+	public int getOperatingLimit() {
+		return operatingLimit < 1 ? RUN_OPERATING_LIMIT : operatingLimit;
+	}
+
+	@Override
+	public void setOperatingLimit(int operatingLimit) {
+		this.operatingLimit = operatingLimit;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public void setFactoryProcessNamePrefix(String factoryProcessNamePrefix) {
+		this.factoryProcessNamePrefix = factoryProcessNamePrefix;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getFactoryProcessNamePrefix() {
+		return factoryProcessNamePrefix == null ? RMI_PREFIX
+				: factoryProcessNamePrefix;
+	}
+
+	@Override
+	public void setExecuteWorkflowScript(String executeWorkflowScript) {
+		this.executeWorkflowScript = executeWorkflowScript;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getExecuteWorkflowScript() {
+		return executeWorkflowScript == null ? defaultExecuteWorkflowScript
+				: executeWorkflowScript;
+	}
+
+	private static String guessWorkflowScript() {
+		File utilDir = new File(DEFAULT_WORKER_JAR).getParentFile();
+		File[] dirs = utilDir.listFiles(new FilenameFilter() {
+			@Override
+			public boolean accept(File dir, String name) {
+				// Support both taverna-commandline* (2.5) and
+				// taverna-command-line* (3.1)
+				return name.toLowerCase().startsWith("taverna-command");
+			}
+		});
+		if (dirs.length == 0) { 
+			throw new IllegalStateException("Can't find taverna-command* distro in " + utilDir);
+		}
+		File script = new File(dirs[0], "executeworkflow.sh");
+		if (! script.isFile()) {
+			throw new IllegalStateException("Can't find launcher script " + script);
+		}
+		return script.toString();
+	}
+
+	/**
+	 * Set what executeworkflow script to use by default. This is the value that
+	 * is used if not overridden by the administration interface.
+	 * 
+	 * @param defaultScript
+	 *            Full path to the script to use.
+	 */
+	public void setDefaultExecuteWorkflowScript(String defaultScript) {
+		if (defaultScript.startsWith("${") || defaultScript.equals("NONE")) {
+			this.defaultExecuteWorkflowScript = guessWorkflowScript();
+			return;
+		}
+		this.defaultExecuteWorkflowScript = defaultScript;
+	}
+
+	String getDefaultExecuteWorkflowScript() {
+		return defaultExecuteWorkflowScript;
+	}
+
+	@Override
+	public void setExtraArgs(String[] extraArgs) {
+		this.extraArgs = extraArgs.clone();
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String[] getExtraArgs() {
+		return extraArgs == null ? EXTRA_ARGUMENTS : extraArgs.clone();
+	}
+
+	@Override
+	public void setWaitSeconds(int waitSeconds) {
+		this.waitSeconds = waitSeconds;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getWaitSeconds() {
+		return waitSeconds < 1 ? SUBPROCESS_START_WAIT : waitSeconds;
+	}
+
+	@Override
+	public void setSleepMS(int sleepMS) {
+		this.sleepMS = sleepMS;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getSleepMS() {
+		return sleepMS < 1 ? SUBPROCESS_START_POLL_SLEEP : sleepMS;
+	}
+
+	@Override
+	public void setServerWorkerJar(String serverWorkerJar) {
+		this.serverWorkerJar = serverWorkerJar;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getServerWorkerJar() {
+		return serverWorkerJar == null ? DEFAULT_WORKER_JAR : serverWorkerJar;
+	}
+
+	@Override
+	public void setServerForkerJar(String serverForkerJar) {
+		this.serverForkerJar = serverForkerJar;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getServerForkerJar() {
+		return serverForkerJar == null ? DEFAULT_FORKER_JAR : serverForkerJar;
+	}
+
+	@Override
+	public void setJavaBinary(String javaBinary) {
+		this.javaBinary = javaBinary;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getJavaBinary() {
+		return javaBinary == null ? DEFAULT_JAVA_BINARY : javaBinary;
+	}
+
+	@Override
+	public void setPasswordFile(String passwordFile) {
+		this.passwordFile = passwordFile;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getPasswordFile() {
+		return passwordFile == null ? defaultPasswordFile : passwordFile;
+	}
+
+	void setDefaultPasswordFile(String defaultPasswordFile) {
+		this.defaultPasswordFile = defaultPasswordFile;
+	}
+
+	@Override
+	public void setRegistryHost(String registryHost) {
+		this.registryHost = (registryHost == null ? "" : registryHost);
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getRegistryHost() {
+		return (registryHost == null || registryHost.isEmpty()) ? null
+				: registryHost;
+	}
+
+	@Override
+	public void setRegistryPort(int registryPort) {
+		this.registryPort = ((registryPort < 1 || registryPort > 65534) ? REGISTRY_PORT
+				: registryPort);
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getRegistryPort() {
+		return registryPort == 0 ? REGISTRY_PORT : registryPort;
+	}
+
+	@Override
+	public String getRegistryJar() {
+		return registryJar == null ? DEFAULT_REGISTRY_JAR : registryJar;
+	}
+
+	@Override
+	public void setRegistryJar(String rmiRegistryJar) {
+		this.registryJar = (rmiRegistryJar == null || rmiRegistryJar.isEmpty()) ? null
+				: rmiRegistryJar;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public List<URI> getPermittedWorkflowURIs() {
+		if (permittedWorkflows == null || permittedWorkflows.length == 0)
+			return emptyList();
+		return unmodifiableList(asList(permittedWorkflows));
+	}
+
+	@Override
+	public void setPermittedWorkflowURIs(List<URI> permittedWorkflows) {
+		if (permittedWorkflows == null || permittedWorkflows.isEmpty())
+			this.permittedWorkflows = new URI[0];
+		else
+			this.permittedWorkflows = permittedWorkflows
+					.toArray(new URI[permittedWorkflows.size()]);
+		if (loadedState)
+			self.store();
+	}
+
+	public static final boolean DEFAULT_GENERATE_PROVENANCE = false;
+	private Boolean generateProvenance;
+
+	@Override
+	public boolean getGenerateProvenance() {
+		Boolean g = generateProvenance;
+		return g == null ? DEFAULT_GENERATE_PROVENANCE : (boolean) g;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean generate) {
+		this.generateProvenance = generate;
+		if (loadedState)
+			self.store();
+	}
+
+	// --------------------------------------------------------------
+
+	private boolean loadedState;
+
+	@PostConstruct
+	@WithinSingleTransaction
+	public void load() {
+		if (loadedState || !isPersistent())
+			return;
+		WorkerModel state = getById(KEY);
+		if (state == null) {
+			store();
+			return;
+		}
+
+		defaultLifetime = state.getDefaultLifetime();
+		executeWorkflowScript = state.getExecuteWorkflowScript();
+		extraArgs = state.getExtraArgs();
+		factoryProcessNamePrefix = state.getFactoryProcessNamePrefix();
+		javaBinary = state.getJavaBinary();
+		maxRuns = state.getMaxRuns();
+		serverWorkerJar = state.getServerWorkerJar();
+		serverForkerJar = state.getServerForkerJar();
+		passwordFile = state.getPasswordFile();
+		sleepMS = state.getSleepMS();
+		waitSeconds = state.getWaitSeconds();
+		registryHost = state.getRegistryHost();
+		registryPort = state.getRegistryPort();
+		operatingLimit = state.getOperatingLimit();
+		List<URI> pwu = state.getPermittedWorkflowURIs();
+		permittedWorkflows = (URI[]) pwu.toArray(new URI[pwu.size()]);
+		registryJar = state.getRegistryJar();
+		generateProvenance = state.getGenerateProvenance();
+
+		loadedState = true;
+	}
+
+	@WithinSingleTransaction
+	public void store() {
+		if (!isPersistent())
+			return;
+		WorkerModel state = getById(KEY);
+		if (state == null)
+			state = persist(makeInstance());
+
+		state.setDefaultLifetime(defaultLifetime);
+		state.setExecuteWorkflowScript(executeWorkflowScript);
+		state.setExtraArgs(extraArgs);
+		state.setFactoryProcessNamePrefix(factoryProcessNamePrefix);
+		state.setJavaBinary(javaBinary);
+		state.setMaxRuns(maxRuns);
+		state.setServerWorkerJar(serverWorkerJar);
+		state.setServerForkerJar(serverForkerJar);
+		state.setPasswordFile(passwordFile);
+		state.setSleepMS(sleepMS);
+		state.setWaitSeconds(waitSeconds);
+		state.setRegistryHost(registryHost);
+		state.setRegistryPort(registryPort);
+		state.setOperatingLimit(operatingLimit);
+		if (permittedWorkflows != null)
+			state.setPermittedWorkflowURIs(asList(permittedWorkflows));
+		state.setRegistryJar(registryJar);
+		if (generateProvenance != null)
+			state.setGenerateProvenance(generateProvenance);
+
+		loadedState = true;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/PersistedState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/PersistedState.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/PersistedState.java
new file mode 100644
index 0000000..3ed4c51
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/PersistedState.java
@@ -0,0 +1,270 @@
+/*
+ */
+package org.taverna.server.master.localworker;
+/*
+ * 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.
+ */
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jdo.annotations.Join;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.PrimaryKey;
+
+import org.taverna.server.master.worker.WorkerModel;
+
+/**
+ * The actual database connector for persisted local worker state.
+ * 
+ * @author Donal Fellows
+ */
+/*
+ * WARNING! If you change the name of this class, update persistence.xml as
+ * well!
+ */
+@PersistenceCapable(table = PersistedState.TABLE)
+class PersistedState implements WorkerModel {
+	static final String TABLE = "LOCALWORKERSTATE__PERSISTEDSTATE";
+
+	static PersistedState makeInstance() {
+		PersistedState o = new PersistedState();
+		o.ID = KEY;
+		return o;
+	}
+
+	@PrimaryKey(column = "ID")
+	protected int ID;
+
+	static final int KEY = 32;
+
+	@Persistent
+	private int defaultLifetime;
+	@Persistent
+	private int maxRuns;
+	@Persistent
+	private String factoryProcessNamePrefix;
+	@Persistent
+	private String executeWorkflowScript;
+	@Persistent(serialized = "true")
+	private String[] extraArgs;
+	@Persistent
+	private int waitSeconds;
+	@Persistent
+	private int sleepMS;
+	@Persistent
+	private String serverWorkerJar;
+	@Persistent
+	private String serverForkerJar;
+	@Persistent
+	private String registryJar;
+	@Persistent
+	private String passwordFile;
+	@Persistent
+	private String javaBinary;
+	@Persistent
+	private int registryPort;
+	@Persistent
+	private String registryHost;
+	@Persistent
+	private int operatingLimit;
+	@Persistent(defaultFetchGroup = "true")
+	@Join(table = TABLE + "_PERMWFURI", column = "ID")
+	private String[] permittedWorkflows;
+	@Persistent
+	private int generateProvenance;
+
+	@Override
+	public void setDefaultLifetime(int defaultLifetime) {
+		this.defaultLifetime = defaultLifetime;
+	}
+
+	@Override
+	public int getDefaultLifetime() {
+		return defaultLifetime;
+	}
+
+	@Override
+	public void setMaxRuns(int maxRuns) {
+		this.maxRuns = maxRuns;
+	}
+
+	@Override
+	public int getMaxRuns() {
+		return maxRuns;
+	}
+
+	@Override
+	public void setFactoryProcessNamePrefix(String factoryProcessNamePrefix) {
+		this.factoryProcessNamePrefix = factoryProcessNamePrefix;
+	}
+
+	@Override
+	public String getFactoryProcessNamePrefix() {
+		return factoryProcessNamePrefix;
+	}
+
+	@Override
+	public void setExecuteWorkflowScript(String executeWorkflowScript) {
+		this.executeWorkflowScript = executeWorkflowScript;
+	}
+
+	@Override
+	public String getExecuteWorkflowScript() {
+		return executeWorkflowScript;
+	}
+
+	@Override
+	public void setExtraArgs(String[] extraArgs) {
+		this.extraArgs = extraArgs;
+	}
+
+	@Override
+	public String[] getExtraArgs() {
+		return extraArgs;
+	}
+
+	@Override
+	public void setWaitSeconds(int waitSeconds) {
+		this.waitSeconds = waitSeconds;
+	}
+
+	@Override
+	public int getWaitSeconds() {
+		return waitSeconds;
+	}
+
+	@Override
+	public void setSleepMS(int sleepMS) {
+		this.sleepMS = sleepMS;
+	}
+
+	@Override
+	public int getSleepMS() {
+		return sleepMS;
+	}
+
+	@Override
+	public void setServerWorkerJar(String serverWorkerJar) {
+		this.serverWorkerJar = serverWorkerJar;
+	}
+
+	@Override
+	public String getServerWorkerJar() {
+		return serverWorkerJar;
+	}
+
+	@Override
+	public void setJavaBinary(String javaBinary) {
+		this.javaBinary = javaBinary;
+	}
+
+	@Override
+	public String getJavaBinary() {
+		return javaBinary;
+	}
+
+	@Override
+	public void setRegistryPort(int registryPort) {
+		this.registryPort = registryPort;
+	}
+
+	@Override
+	public int getRegistryPort() {
+		return registryPort;
+	}
+
+	@Override
+	public void setRegistryHost(String registryHost) {
+		this.registryHost = registryHost;
+	}
+
+	@Override
+	public String getRegistryHost() {
+		return registryHost;
+	}
+
+	@Override
+	public void setServerForkerJar(String serverForkerJar) {
+		this.serverForkerJar = serverForkerJar;
+	}
+
+	@Override
+	public String getServerForkerJar() {
+		return serverForkerJar;
+	}
+
+	@Override
+	public void setPasswordFile(String passwordFile) {
+		this.passwordFile = passwordFile;
+	}
+
+	@Override
+	public String getPasswordFile() {
+		return passwordFile;
+	}
+
+	@Override
+	public void setOperatingLimit(int operatingLimit) {
+		this.operatingLimit = operatingLimit;
+	}
+
+	@Override
+	public int getOperatingLimit() {
+		return operatingLimit;
+	}
+
+	@Override
+	public List<URI> getPermittedWorkflowURIs() {
+		String[] pw = this.permittedWorkflows;
+		if (pw == null)
+			return new ArrayList<>();
+		List<URI> uris = new ArrayList<>(pw.length);
+		for (String uri : pw)
+			uris.add(URI.create(uri));
+		return uris;
+	}
+
+	@Override
+	public void setPermittedWorkflowURIs(List<URI> permittedWorkflows) {
+		String[] pw = new String[permittedWorkflows.size()];
+		for (int i = 0; i < pw.length; i++)
+			pw[i] = permittedWorkflows.get(i).toString();
+		this.permittedWorkflows = pw;
+	}
+
+	@Override
+	public String getRegistryJar() {
+		return registryJar;
+	}
+
+	@Override
+	public void setRegistryJar(String registryJar) {
+		this.registryJar = registryJar;
+	}
+
+	@Override
+	public boolean getGenerateProvenance() {
+		return generateProvenance > 0;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean generateProvenance) {
+		this.generateProvenance = (generateProvenance ? 1 : 0);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/StreamLogger.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/StreamLogger.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/StreamLogger.java
new file mode 100644
index 0000000..e563965
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/StreamLogger.java
@@ -0,0 +1,78 @@
+package org.taverna.server.master.localworker;
+/*
+ * 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.
+ */
+
+import static java.lang.Thread.interrupted;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.commons.logging.Log;
+
+abstract class StreamLogger {
+	protected final Log log;
+	private Thread t;
+	private InputStream in;
+
+	protected StreamLogger(final String name, InputStream is) {
+		log = getLog("Taverna.Server.LocalWorker." + name);
+		in = is;
+		t = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				try (BufferedReader br = new BufferedReader(
+						new InputStreamReader(in))) {
+					String line;
+					while (!interrupted() && (line = br.readLine()) != null)
+						if (!line.isEmpty())
+							write(line);
+				} catch (IOException e) {
+					// Do nothing...
+				} catch (Exception e) {
+					log.warn("failure in reading from " + name, e);
+				}
+			}
+		}, name + ".StreamLogger");
+		t.setContextClassLoader(null);
+		t.setDaemon(true);
+		t.start();
+	}
+
+	/**
+	 * Write a line read from the subprocess to the log.
+	 * <p>
+	 * This needs to be implemented by subclasses in order for the log to be
+	 * correctly written with the class name.
+	 * 
+	 * @param msg
+	 *            The message to write. Guaranteed to have no newline characters
+	 *            in it and to be non-empty.
+	 */
+	protected abstract void write(String msg);
+
+	public void stop() {
+		log.info("trying to close down " + t.getName());
+		t.interrupt();
+		try {
+			in.close();
+		} catch (IOException e) {
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/package-info.java
new file mode 100644
index 0000000..031ce34
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/localworker/package-info.java
@@ -0,0 +1,23 @@
+/*
+ */
+/**
+ * Implementation of a Taverna Server back-end that works by forking off
+ * workflow executors on the local system.
+ */
+package org.taverna.server.master.localworker;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/EmailDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/EmailDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/EmailDispatcher.java
new file mode 100644
index 0000000..2a51496
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/EmailDispatcher.java
@@ -0,0 +1,126 @@
+/*
+ */
+package org.taverna.server.master.notification;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.mail.MailSender;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+
+/**
+ * How to send a plain text message by email to someone.
+ * 
+ * @author Donal Fellows
+ */
+public class EmailDispatcher extends RateLimitedDispatcher {
+	@Override
+	public String getName() {
+		return "mailto";
+	}
+
+	/**
+	 * @param from
+	 *            Email address that the notification is to come from.
+	 */
+	@Required
+	public void setFrom(String from) {
+		this.from = valid(from, "");
+	}
+
+	/**
+	 * @param host
+	 *            The outgoing SMTP server address.
+	 */
+	@Required
+	public void setSmtpHost(String host) {
+		this.host = valid(host, "");
+	}
+
+	/**
+	 * @param contentType
+	 *            The content type of the message to be sent. For example, "
+	 *            <tt>text/plain</tt>".
+	 */
+	public void setMessageContentType(String contentType) {
+		this.contentType = contentType;
+	}
+
+	/**
+	 * @param sender
+	 *            the sender to set
+	 */
+	public void setSender(MailSender sender) {
+		this.sender = sender;
+	}
+
+	private String from;
+	private String host;
+	private MailSender sender;
+	@SuppressWarnings("unused")
+	private String contentType = TEXT_PLAIN;
+
+	/**
+	 * Try to perform the lookup of the email service. This is called during
+	 * configuration so that any failure happens at a useful, predictable time.
+	 */
+	@PostConstruct
+	public void tryLookup() {
+		if (!isAvailable()) {
+			log.warn("no mail support; disabling email dispatch");
+			sender = null;
+			return;
+		}
+		try {
+			if (sender instanceof JavaMailSender)
+				((JavaMailSender) sender).createMimeMessage();
+		} catch (Throwable t) {
+			log.warn("sender having problems constructing messages; "
+					+ "disabling...", t);
+			sender = null;
+		}
+	}
+
+	@Override
+	public void dispatch(String messageSubject, String messageContent, String to)
+			throws Exception {
+		// Simple checks for acceptability
+		if (!to.matches(".+@.+")) {
+			log.info("did not send email notification: improper email address \""
+					+ to + "\"");
+			return;
+		}
+
+		SimpleMailMessage message = new SimpleMailMessage();
+		message.setFrom(from);
+		message.setTo(to.trim());
+		message.setSubject(messageSubject);
+		message.setText(messageContent);
+		sender.send(message);
+	}
+
+	@Override
+	public boolean isAvailable() {
+		return (host != null && !host.isEmpty() && sender != null
+				&& from != null && !from.isEmpty());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/JabberDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/JabberDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/JabberDispatcher.java
new file mode 100644
index 0000000..711f4e6
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/JabberDispatcher.java
@@ -0,0 +1,153 @@
+/*
+ */
+
+package org.taverna.server.master.notification;
+/*
+ * 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.
+ */
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jivesoftware.smack.Chat;
+import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.MessageListener;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.packet.Message;
+import org.taverna.server.master.interfaces.MessageDispatcher;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * Send notifications by Jabber/XMPP.
+ * 
+ * @author Donal Fellows
+ */
+public class JabberDispatcher implements MessageDispatcher {
+	@Override
+	public String getName() {
+		return "xmpp";
+	}
+
+	private Log log = LogFactory.getLog("Taverna.Server.Notification");
+	private XMPPConnection conn;
+	private String resource = "TavernaServer";
+	private String host = "";
+	private String user = "";
+	private String pass = "";
+
+	/**
+	 * @param resource
+	 *            The XMPP resource to use when connecting the server. This
+	 *            defaults to "<tt>TavernaServer</tt>".
+	 */
+	public void setResource(String resource) {
+		this.resource = resource;
+	}
+
+	/**
+	 * @param service
+	 *            The XMPP service URL.
+	 */
+	public void setHost(String service) {
+		if (service == null || service.trim().isEmpty()
+				|| service.trim().startsWith("$"))
+			this.host = "";
+		else
+			this.host = service.trim();
+	}
+
+	/**
+	 * @param user
+	 *            The user identity to use with the XMPP service.
+	 */
+	public void setUsername(String user) {
+		if (user == null || user.trim().isEmpty()
+				|| user.trim().startsWith("$"))
+			this.user = "";
+		else
+			this.user = user.trim();
+	}
+
+	/**
+	 * @param pass
+	 *            The password to use with the XMPP service.
+	 */
+	public void setPassword(String pass) {
+		if (pass == null || pass.trim().isEmpty()
+				|| pass.trim().startsWith("$"))
+			this.pass = "";
+		else
+			this.pass = pass.trim();
+	}
+
+	@PostConstruct
+	void setup() {
+		try {
+			if (host.isEmpty() || user.isEmpty() || pass.isEmpty()) {
+				log.info("disabling XMPP support; incomplete configuration");
+				conn = null;
+				return;
+			}
+			ConnectionConfiguration cfg = new ConnectionConfiguration(host);
+			cfg.setSendPresence(false);
+			XMPPConnection c = new XMPPConnection(cfg);
+			c.connect();
+			c.login(user, pass, resource);
+			conn = c;
+			log.info("connected to XMPP service <" + host + "> as user <"
+					+ user + ">");
+		} catch (Exception e) {
+			log.info("failed to connect to XMPP server", e);
+		}
+	}
+
+	@PreDestroy
+	public void close() {
+		if (conn != null)
+			conn.disconnect();
+		conn = null;
+	}
+
+	@Override
+	public boolean isAvailable() {
+		return conn != null;
+	}
+
+	@Override
+	public void dispatch(TavernaRun ignored, String messageSubject,
+			String messageContent, String targetParameter) throws Exception {
+		Chat chat = conn.getChatManager().createChat(targetParameter,
+				new DroppingListener());
+		Message m = new Message();
+		m.addBody(null, messageContent);
+		m.setSubject(messageSubject);
+		chat.sendMessage(m);
+	}
+
+	static class DroppingListener implements MessageListener {
+		private Log log = LogFactory
+				.getLog("Taverna.Server.Notification.Jabber");
+
+		@Override
+		public void processMessage(Chat chat, Message message) {
+			if (log.isDebugEnabled())
+				log.debug("unexpectedly received XMPP message from <"
+						+ message.getFrom() + ">; ignoring");
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/NotificationEngine.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/NotificationEngine.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/NotificationEngine.java
new file mode 100644
index 0000000..067d154
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/NotificationEngine.java
@@ -0,0 +1,158 @@
+/*
+ */
+package org.taverna.server.master.notification;
+/*
+ * 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.
+ */
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.interfaces.MessageDispatcher;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * A common object for handling dispatch of event-driven messages.
+ * 
+ * @author Donal Fellows
+ */
+public class NotificationEngine {
+	private Log log = LogFactory.getLog("Taverna.Server.Notification");
+	private Map<String, MessageDispatcher> dispatchers;
+	private List<MessageDispatcher> universalDispatchers;
+
+	/**
+	 * @param dispatchers
+	 *            The various dispatchers we want to install.
+	 */
+	@Required
+	public void setDispatchers(List<MessageDispatcher> dispatchers) {
+		this.dispatchers = new HashMap<>();
+		for (MessageDispatcher d : dispatchers)
+			this.dispatchers.put(d.getName(), d);
+	}
+
+	/**
+	 * @param dispatcherList
+	 *            A list of dispatch objects to always dispatch to.
+	 */
+	@Required
+	public void setUniversalDispatchers(List<MessageDispatcher> dispatcherList) {
+		this.universalDispatchers = dispatcherList;
+	}
+
+	private void dispatchToChosenTarget(TavernaRun originator, String scheme,
+			String target, Message message) throws Exception {
+		try {
+			MessageDispatcher d = dispatchers.get(scheme);
+			if (d != null && d.isAvailable())
+				d.dispatch(originator, message.getTitle(scheme),
+						message.getContent(scheme), target);
+			else
+				log.warn("no such notification dispatcher for " + scheme);
+		} catch (URISyntaxException e) {
+			// See if *someone* will handle the message
+			Exception e2 = null;
+			for (MessageDispatcher d : dispatchers.values())
+				try {
+					if (d.isAvailable()) {
+						d.dispatch(originator, message.getTitle(d.getName()),
+								message.getContent(d.getName()), scheme + ":"
+										+ target);
+						return;
+					}
+				} catch (Exception ex) {
+					if (log.isDebugEnabled())
+						log.debug("failed in pseudo-directed dispatch of "
+								+ scheme + ":" + target, ex);
+					e2 = ex;
+				}
+			if (e2 != null)
+				throw e2;
+		}
+	}
+
+	private void dispatchUniversally(TavernaRun originator, Message message)
+			throws Exception {
+		for (MessageDispatcher d : universalDispatchers)
+			try {
+				if (d.isAvailable())
+					d.dispatch(originator, message.getTitle(d.getName()),
+							message.getContent(d.getName()), null);
+			} catch (Exception e) {
+				log.warn("problem in universal dispatcher", e);
+			}
+	}
+
+	/**
+	 * Dispatch a message over the notification fabric.
+	 * 
+	 * @param originator
+	 *            What workflow run was the source of this message?
+	 * @param destination
+	 *            Where the message should get delivered to. The correct format
+	 *            of this is either as a URI of some form (where the scheme
+	 *            determines the dispatcher) or as an invalid URI in which case
+	 *            it is just tried against the possibilities to see if any
+	 *            succeeds.
+	 * @param subject
+	 *            The subject line of the message.
+	 * @param message
+	 *            The plain text body of the message.
+	 * @throws Exception
+	 *             If anything goes wrong with the dispatch process.
+	 */
+	public void dispatchMessage(TavernaRun originator, String destination,
+			Message message) throws Exception {
+		if (destination != null && !destination.trim().isEmpty()) {
+			try {
+				URI toURI = new URI(destination.trim());
+				dispatchToChosenTarget(originator, toURI.getScheme(),
+						toURI.getSchemeSpecificPart(), message);
+			} catch (URISyntaxException e) {
+				// Ignore
+			}
+		}
+		dispatchUniversally(originator, message);
+	}
+
+	/**
+	 * @return The message dispatchers that are actually available (i.e., not
+	 *         disabled by configuration somewhere).
+	 */
+	public List<String> listAvailableDispatchers() {
+		ArrayList<String> result = new ArrayList<>();
+		for (Map.Entry<String, MessageDispatcher> entry : dispatchers
+				.entrySet()) {
+			if (entry.getValue().isAvailable())
+				result.add(entry.getKey());
+		}
+		return result;
+	}
+
+	public interface Message {
+		String getContent(String type);
+
+		String getTitle(String type);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/RateLimitedDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/RateLimitedDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/RateLimitedDispatcher.java
new file mode 100644
index 0000000..a41e23b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/RateLimitedDispatcher.java
@@ -0,0 +1,102 @@
+/*
+ */
+package org.taverna.server.master.notification;
+/*
+ * 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.
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.DateTime;
+import org.taverna.server.master.interfaces.MessageDispatcher;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * Rate-limiting support. Some message fabrics simply should not be used to send
+ * a lot of messages.
+ * 
+ * @author Donal Fellows
+ */
+public abstract class RateLimitedDispatcher implements MessageDispatcher {
+	/** Pre-configured logger. */
+	protected Log log = LogFactory.getLog("Taverna.Server.Notification");
+	private int cooldownSeconds;
+	private Map<String, DateTime> lastSend = new HashMap<>();
+
+	String valid(String value, String def) {
+		if (value == null || value.trim().isEmpty()
+				|| value.trim().startsWith("${"))
+			return def;
+		else
+			return value.trim();
+	}
+
+	/**
+	 * Set how long must elapse between updates to the status of any particular
+	 * user. Calls before that time are just silently dropped.
+	 * 
+	 * @param cooldownSeconds
+	 *            Time to elapse, in seconds.
+	 */
+	public void setCooldownSeconds(int cooldownSeconds) {
+		this.cooldownSeconds = cooldownSeconds;
+	}
+
+	/**
+	 * Test whether the rate limiter allows the given user to send a message.
+	 * 
+	 * @param who
+	 *            Who wants to send the message?
+	 * @return <tt>true</tt> iff they are permitted.
+	 */
+	protected boolean isSendAllowed(String who) {
+		DateTime now = new DateTime();
+		synchronized (lastSend) {
+			DateTime last = lastSend.get(who);
+			if (last != null) {
+				if (!now.isAfter(last.plusSeconds(cooldownSeconds)))
+					return false;
+			}
+			lastSend.put(who, now);
+		}
+		return true;
+	}
+
+	@Override
+	public void dispatch(TavernaRun ignored, String messageSubject,
+			String messageContent, String target) throws Exception {
+		if (isSendAllowed(target))
+			dispatch(messageSubject, messageContent, target);
+	}
+
+	/**
+	 * Dispatch a message to a recipient that doesn't care what produced it.
+	 * 
+	 * @param messageSubject
+	 *            The subject of the message to send.
+	 * @param messageContent
+	 *            The plain-text content of the message to send.
+	 * @param target
+	 *            A description of where it is to go.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	public abstract void dispatch(String messageSubject, String messageContent,
+			String target) throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/SMSDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/SMSDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/SMSDispatcher.java
new file mode 100644
index 0000000..559f111
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/SMSDispatcher.java
@@ -0,0 +1,171 @@
+/*
+ */
+package org.taverna.server.master.notification;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.defaults.Default.SMS_GATEWAY_URL;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.message.BasicNameValuePair;
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * Dispatch termination messages via SMS.
+ * 
+ * @author Donal Fellows
+ */
+public class SMSDispatcher extends RateLimitedDispatcher {
+	@Override
+	public String getName() {
+		return "sms";
+	}
+
+	private CloseableHttpClient client;
+	private URI service;
+	private String user = "", pass = "";
+	private String usernameField = "username", passwordField = "password",
+			destinationField = "to", messageField = "text";
+
+	/**
+	 * @param usernameField
+	 *            The name of the field that conveys the sending username; this
+	 *            is the <i>server</i>'s identity.
+	 */
+	@Required
+	public void setUsernameField(String usernameField) {
+		this.usernameField = usernameField;
+	}
+
+	/**
+	 * @param passwordField
+	 *            The field holding the password to authenticate the server to
+	 *            the SMS gateway.
+	 */
+	@Required
+	public void setPasswordField(String passwordField) {
+		this.passwordField = passwordField;
+	}
+
+	/**
+	 * @param destinationField
+	 *            The field holding the number to send the SMS to.
+	 */
+	@Required
+	public void setDestinationField(String destinationField) {
+		this.destinationField = destinationField;
+	}
+
+	/**
+	 * @param messageField
+	 *            The field holding the plain-text message to send.
+	 */
+	@Required
+	public void setMessageField(String messageField) {
+		this.messageField = messageField;
+	}
+
+	public void setService(String serviceURL) {
+		String s = valid(serviceURL, "");
+		if (s.isEmpty()) {
+			log.warn("did not get sms.service from servlet config; using default ("
+					+ SMS_GATEWAY_URL + ")");
+			s = SMS_GATEWAY_URL;
+		}
+		try {
+			service = new URI(s);
+		} catch (URISyntaxException e) {
+			service = null;
+		}
+	}
+
+	public void setUser(String user) {
+		this.user = valid(user, "");
+	}
+
+	public void setPassword(String pass) {
+		this.pass = valid(pass, "");
+	}
+
+	@PostConstruct
+	void init() {
+		client = HttpClientBuilder.create().build();
+	}
+
+	@PreDestroy
+	void close() throws IOException {
+		try {
+			if (client != null)
+				client.close();
+		} finally {
+			client = null;
+		}
+	}
+
+	@Override
+	public boolean isAvailable() {
+		return service != null && !user.isEmpty() && !pass.isEmpty();
+	}
+
+	@Override
+	public void dispatch(String messageSubject, String messageContent,
+			String targetParameter) throws Exception {
+		// Sanity check
+		if (!targetParameter.matches("[^0-9]+"))
+			throw new Exception("invalid phone number");
+
+		if (!isSendAllowed("anyone"))
+			return;
+
+		// Build the message to send
+		List<NameValuePair> params = new ArrayList<>();
+		params.add(new BasicNameValuePair(usernameField, user));
+		params.add(new BasicNameValuePair(passwordField, pass));
+		params.add(new BasicNameValuePair(destinationField, targetParameter));
+		params.add(new BasicNameValuePair(messageField, messageContent));
+
+		// Send the message
+		HttpPost post = new HttpPost(service);
+		post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
+		HttpResponse response = client.execute(post);
+
+		// Log the response
+		HttpEntity entity = response.getEntity();
+		if (entity != null)
+			try (BufferedReader e = new BufferedReader(new InputStreamReader(
+					entity.getContent()))) {
+				log.info(e.readLine());
+			}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/TwitterDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/TwitterDispatcher.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/TwitterDispatcher.java
new file mode 100644
index 0000000..a0269a5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/TwitterDispatcher.java
@@ -0,0 +1,145 @@
+/*
+ */
+package org.taverna.server.master.notification;
+/*
+ * 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.
+ */
+
+import java.util.Properties;
+
+import twitter4j.Twitter;
+import twitter4j.TwitterFactory;
+import twitter4j.conf.Configuration;
+import twitter4j.conf.PropertyConfiguration;
+import twitter4j.auth.AuthorizationFactory;
+
+/**
+ * Super simple-minded twitter dispatcher. You need to tell it your consumer key
+ * and secret as part of the connection parameters, for example via a dispatcher
+ * URN of "<tt>twitter:fred:bloggs</tt>" where <tt>fred</tt> is the key and
+ * <tt>bloggs</tt> is the secret.
+ * 
+ * @author Donal Fellows
+ */
+public class TwitterDispatcher extends RateLimitedDispatcher {
+	@Override
+	public String getName() {
+		return "twitter";
+	}
+
+	public static final int MAX_MESSAGE_LENGTH = 140;
+	public static final char ELLIPSIS = '\u2026';
+
+	private String token = "";
+	private String secret = "";
+
+	public void setAccessToken(String token) {
+		this.token = valid(token, "");
+	}
+
+	public void setAccessSecret(String secret) {
+		this.secret = valid(secret, "");
+	}
+
+	private Properties getConfig() throws NotConfiguredException {
+		if (token.isEmpty() || secret.isEmpty())
+			throw new NotConfiguredException();
+		Properties p = new Properties();
+		p.setProperty(ACCESS_TOKEN_PROP, token);
+		p.setProperty(ACCESS_SECRET_PROP, secret);
+		return p;
+	}
+
+	public static final String ACCESS_TOKEN_PROP = "oauth.accessToken";
+	public static final String ACCESS_SECRET_PROP = "oauth.accessTokenSecret";
+
+	private Twitter getTwitter(String key, String secret) throws Exception {
+		if (key.isEmpty() || secret.isEmpty())
+			throw new NoCredentialsException();
+
+		Properties p = getConfig();
+		p.setProperty("oauth.consumerKey", key);
+		p.setProperty("oauth.consumerSecret", secret);
+
+		Configuration config = new PropertyConfiguration(p);
+		TwitterFactory factory = new TwitterFactory(config);
+		Twitter t = factory.getInstance(AuthorizationFactory
+				.getInstance(config));
+		// Verify that we can connect!
+		t.getOAuthAccessToken();
+		return t;
+	}
+
+	// TODO: Get secret from credential manager
+	@Override
+	public void dispatch(String messageSubject, String messageContent,
+			String targetParameter) throws Exception {
+		// messageSubject ignored
+		String[] target = targetParameter.split(":", 2);
+		if (target == null || target.length != 2)
+			throw new Exception("missing consumer key or secret");
+		String who = target[0];
+		if (!isSendAllowed(who))
+			return;
+		Twitter twitter = getTwitter(who, target[1]);
+
+		if (messageContent.length() > MAX_MESSAGE_LENGTH)
+			messageContent = messageContent
+					.substring(0, MAX_MESSAGE_LENGTH - 1) + ELLIPSIS;
+		twitter.updateStatus(messageContent);
+	}
+
+	@Override
+	public boolean isAvailable() {
+		try {
+			// Try to create the configuration and push it through as far as
+			// confirming that we can build an access object (even if it isn't
+			// bound to a user)
+			new TwitterFactory(new PropertyConfiguration(getConfig()))
+					.getInstance();
+			return true;
+		} catch (Exception e) {
+			return false;
+		}
+	}
+
+	/**
+	 * Indicates that the dispatcher has not been configured with service
+	 * credentials.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@SuppressWarnings("serial")
+	public static class NotConfiguredException extends Exception {
+		NotConfiguredException() {
+			super("not configured with xAuth key and secret; "
+					+ "dispatch not possible");
+		}
+	}
+
+	/**
+	 * Indicates that the user did not supply their credentials.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@SuppressWarnings("serial")
+	public static class NoCredentialsException extends Exception {
+		NoCredentialsException() {
+			super("no consumer key and secret present; "
+					+ "dispatch not possible");
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/AtomFeed.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/AtomFeed.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/AtomFeed.java
new file mode 100644
index 0000000..eda6d9d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/AtomFeed.java
@@ -0,0 +1,147 @@
+/*
+ */
+package org.taverna.server.master.notification.atom;
+/*
+ * 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.
+ */
+
+import static java.lang.String.format;
+import static java.util.UUID.randomUUID;
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.common.Uri.secure;
+
+import java.net.URI;
+import java.util.Date;
+
+import javax.annotation.security.RolesAllowed;
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.web.context.ServletContextAware;
+import org.taverna.server.master.TavernaServerSupport;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.rest.TavernaServerREST.EventFeed;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * Simple REST handler that allows an Atom feed to be served up of events
+ * generated by workflow runs.
+ * 
+ * @author Donal Fellows
+ */
+public class AtomFeed implements EventFeed, UriBuilderFactory,
+		ServletContextAware {
+	/**
+	 * The name of a parameter that states what address we should claim that the
+	 * feed's internally-generated URIs are relative to. If not set, a default
+	 * will be guessed.
+	 */
+	public static final String PREFERRED_URI_PARAM = "taverna.preferredUserUri";
+	private EventDAO eventSource;
+	private TavernaServerSupport support;
+	private URI baseURI;
+	private Abdera abdera;
+	private String feedLanguage = "en";
+	private String uuid = randomUUID().toString();
+
+	@Required
+	public void setEventSource(EventDAO eventSource) {
+		this.eventSource = eventSource;
+	}
+
+	@Required
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	public void setFeedLanguage(String language) {
+		this.feedLanguage = language;
+	}
+
+	public String getFeedLanguage() {
+		return feedLanguage;
+	}
+
+	@Required
+	public void setAbdera(Abdera abdera) {
+		this.abdera = abdera;
+	}
+
+	@Override
+	@CallCounted
+	@RolesAllowed(USER)
+	public Feed getFeed(UriInfo ui) {
+		Feed feed = abdera.getFactory().newFeed();
+		feed.setTitle("events relating to workflow runs").setLanguage(
+				feedLanguage);
+		String user = support.getPrincipal().toString()
+				.replaceAll("[^A-Za-z0-9]+", "");
+		feed.setId(format("urn:taverna-server:%s:%s", uuid, user));
+		org.joda.time.DateTime modification = null;
+		for (Event e : eventSource.getEvents(support.getPrincipal())) {
+			if (modification == null || e.getPublished().isAfter(modification))
+				modification = e.getPublished();
+			feed.addEntry(e.getEntry(abdera, feedLanguage));
+		}
+		if (modification == null)
+			feed.setUpdated(new Date());
+		else
+			feed.setUpdated(modification.toDate());
+		feed.addLink(ui.getAbsolutePath().toASCIIString(), "self");
+		return feed;
+	}
+
+	@Override
+	@CallCounted
+	@RolesAllowed(USER)
+	public Entry getEvent(String id) {
+		return eventSource.getEvent(support.getPrincipal(), id).getEntry(
+				abdera, feedLanguage);
+	}
+
+	@Override
+	public UriBuilder getRunUriBuilder(TavernaRun run) {
+		return secure(fromUri(getBaseUriBuilder().path("runs/{uuid}").build(
+				run.getId())));
+	}
+
+	@Override
+	public UriBuilder getBaseUriBuilder() {
+		return secure(fromUri(baseURI));
+	}
+
+	@Override
+	public String resolve(String uri) {
+		if (uri == null)
+			return null;
+		return secure(baseURI, uri).toString();
+	}
+
+	@Override
+	public void setServletContext(ServletContext servletContext) {
+		String base = servletContext.getInitParameter(PREFERRED_URI_PARAM);
+		if (base == null)
+			base = servletContext.getContextPath() + "/rest";
+		baseURI = URI.create(base);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/Event.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/Event.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/Event.java
new file mode 100644
index 0000000..f1a9d62
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/Event.java
@@ -0,0 +1,123 @@
+/*
+ */
+package org.taverna.server.master.notification.atom;
+/*
+ * 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.
+ */
+
+import static java.util.UUID.randomUUID;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Date;
+
+import javax.jdo.annotations.Column;
+import javax.jdo.annotations.Index;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.Queries;
+import javax.jdo.annotations.Query;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Entry;
+import org.joda.time.DateTime;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Parent class of all events that may appear on the feed for a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+@PersistenceCapable(schema = "ATOM", table = "EVENTS")
+@Queries({
+		@Query(name = "eventsForUser", language = "SQL", value = "SELECT id FROM ATOM.EVENTS WHERE owner = ? ORDER BY published DESC", resultClass = String.class),
+		@Query(name = "eventForUserAndId", language = "SQL", value = "SELECT id FROM ATOM.EVENTS WHERE owner = ? AND id = ?", resultClass = String.class),
+		@Query(name = "eventsFromBefore", language = "SQL", value = "SELECT id FROM ATOM.EVENTS where published < ?", resultClass = String.class) })
+public class Event implements Serializable {
+	@Persistent(primaryKey = "true")
+	@Column(length = 48)
+	private String id;
+	@Persistent
+	private String owner;
+	@Persistent
+	@Index
+	private Date published;
+	@Persistent
+	private String message;
+	@Persistent
+	private String title;
+	@Persistent
+	private String link;
+
+	Event() {
+	}
+
+	/**
+	 * Initialise the identity of this event and the point at which it was
+	 * published.
+	 * 
+	 * @param idPrefix
+	 *            A prefix for the identity of this event.
+	 * @param owner
+	 *            Who is the owner of this event.
+	 */
+	Event(String idPrefix, URI workflowLink, UsernamePrincipal owner,
+			String title, String message) {
+		id = idPrefix + "." + randomUUID().toString();
+		published = new Date();
+		this.owner = owner.getName();
+		this.title = title;
+		this.message = message;
+		this.link = workflowLink.toASCIIString();
+	}
+
+	public final String getId() {
+		return id;
+	}
+
+	public final String getOwner() {
+		return owner;
+	}
+
+	public final DateTime getPublished() {
+		return new DateTime(published);
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public String getLink() {
+		return link;
+	}
+
+	public Entry getEntry(Abdera abdera, String language) {
+		Entry entry = abdera.getFactory().newEntry();
+		entry.setId(id);
+		entry.setPublished(published);
+		entry.addAuthor(owner).setLanguage(language);
+		entry.setUpdated(published);
+		entry.setTitle(title).setLanguage(language);
+		entry.addLink(link, "related").setTitle("workflow run");
+		entry.setContent(message).setLanguage(language);
+		return entry;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/EventDAO.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/EventDAO.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/EventDAO.java
new file mode 100644
index 0000000..8bec456
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/EventDAO.java
@@ -0,0 +1,230 @@
+/*
+ */
+package org.taverna.server.master.notification.atom;
+/*
+ * 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.
+ */
+
+import static java.lang.Thread.interrupted;
+import static java.lang.Thread.sleep;
+import static java.util.Arrays.asList;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PreDestroy;
+import javax.jdo.annotations.PersistenceAware;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.DateTime;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.interfaces.MessageDispatcher;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.utils.JDOSupport;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * The database interface that supports the event feed.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceAware
+public class EventDAO extends JDOSupport<Event> implements MessageDispatcher {
+	public EventDAO() {
+		super(Event.class);
+	}
+
+	@Override
+	public String getName() {
+		return "atom";
+	}
+
+	private Log log = LogFactory.getLog("Taverna.Server.Atom");
+	private UriBuilderFactory ubf;
+	private int expiryAgeDays;
+
+	@Required
+	public void setExpiryAgeDays(int expiryAgeDays) {
+		this.expiryAgeDays = expiryAgeDays;
+	}
+
+	@Required
+	public void setUriBuilderFactory(UriBuilderFactory ubf) {
+		this.ubf = ubf;
+	}
+
+	/**
+	 * Get the given user's list of events.
+	 * 
+	 * @param user
+	 *            The identity of the user to get the events for.
+	 * @return A copy of the list of events currently known about.
+	 */
+	@Nonnull
+	@WithinSingleTransaction
+	public List<Event> getEvents(@Nonnull UsernamePrincipal user) {
+		List<String> ids = eventsForUser(user);
+		if (log.isDebugEnabled())
+			log.debug("found " + ids.size() + " events for user " + user);
+
+		List<Event> result = new ArrayList<>();
+		for (String id : ids) {
+			Event event = getById(id);
+			result.add(detach(event));
+		}
+		return result;
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> eventsForUser(UsernamePrincipal user) {
+		return (List<String>) namedQuery("eventsForUser").execute(
+				user.getName());
+	}
+
+	/**
+	 * Get a particular event.
+	 * 
+	 * @param user
+	 *            The identity of the user to get the event for.
+	 * @param id
+	 *            The handle of the event to look up.
+	 * @return A copy of the event.
+	 */
+	@Nonnull
+	@WithinSingleTransaction
+	public Event getEvent(@Nonnull UsernamePrincipal user, @Nonnull String id) {
+		List<String> ids = eventsForUserAndId(user, id);
+		if (log.isDebugEnabled())
+			log.debug("found " + ids.size() + " events for user " + user
+					+ " with id = " + id);
+
+		if (ids.size() != 1)
+			throw new IllegalArgumentException("no such id");
+		return detach(getById(ids.get(0)));
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> eventsForUserAndId(UsernamePrincipal user, String id) {
+		return (List<String>) namedQuery("eventForUserAndId").execute(
+				user.getName(), id);
+	}
+
+	/**
+	 * Delete a particular event.
+	 * 
+	 * @param id
+	 *            The identifier of the event to delete.
+	 */
+	@WithinSingleTransaction
+	public void deleteEventById(@Nonnull String id) {
+		delete(getById(id));
+	}
+
+	/**
+	 * Delete all events that have expired.
+	 */
+	@WithinSingleTransaction
+	public void deleteExpiredEvents() {
+		Date death = new DateTime().plusDays(-expiryAgeDays).toDate();
+		death = new Timestamp(death.getTime()); // UGLY SQL HACK
+
+		List<String> ids = eventsFromBefore(death);
+		if (log.isDebugEnabled() && !ids.isEmpty())
+			log.debug("found " + ids.size()
+					+ " events to be squelched (older than " + death + ")");
+
+		for (String id : ids)
+			delete(getById(id));
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> eventsFromBefore(Date death) {
+		return (List<String>) namedQuery("eventsFromBefore").execute(death);
+	}
+
+	@Override
+	public boolean isAvailable() {
+		return true;
+	}
+
+	private BlockingQueue<Event> insertQueue = new ArrayBlockingQueue<>(16);
+
+	@Override
+	public void dispatch(TavernaRun originator, String messageSubject,
+			String messageContent, String targetParameter) throws Exception {
+		insertQueue.put(new Event("finish", ubf.getRunUriBuilder(originator)
+				.build(), originator.getSecurityContext().getOwner(),
+				messageSubject, messageContent));
+	}
+
+	public void started(TavernaRun originator, String messageSubject,
+			String messageContent) throws InterruptedException {
+		insertQueue.put(new Event("start", ubf.getRunUriBuilder(originator)
+				.build(), originator.getSecurityContext().getOwner(),
+				messageSubject, messageContent));
+	}
+
+	private Thread eventDaemon;
+	private boolean shuttingDown = false;
+
+	@Required
+	public void setSelf(final EventDAO dao) {
+		eventDaemon = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					while (!shuttingDown && !interrupted()) {
+						transferEvents(dao, new ArrayList<Event>(
+								asList(insertQueue.take())));
+						sleep(5000);
+					}
+				} catch (InterruptedException e) {
+				} finally {
+					transferEvents(dao, new ArrayList<Event>());
+				}
+			}
+		}, "ATOM event daemon");
+		eventDaemon.setContextClassLoader(null);
+		eventDaemon.setDaemon(true);
+		eventDaemon.start();
+	}
+
+	private void transferEvents(EventDAO dao, List<Event> e) {
+		insertQueue.drainTo(e);
+		dao.storeEvents(e);
+	}
+
+	@PreDestroy
+	void stopDaemon() {
+		shuttingDown = true;
+		if (eventDaemon != null)
+			eventDaemon.interrupt();
+	}
+
+	@WithinSingleTransaction
+	protected void storeEvents(List<Event> events) {
+		for (Event e : events)
+			persist(e);
+		log.info("stored " + events.size() + " notification events");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/package-info.java
new file mode 100644
index 0000000..0a1a52f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/atom/package-info.java
@@ -0,0 +1,42 @@
+/*
+ */
+/**
+ * This package contains the Atom feed implementation within Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = FEED, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.notification.atom;
+/*
+ * 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.
+ */
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.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/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/package-info.java
new file mode 100644
index 0000000..43335cf
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/notification/package-info.java
@@ -0,0 +1,23 @@
+/*
+ */
+/**
+ * The notification fabric and implementations of notification dispatchers
+ * that support subscription.
+ */
+package org.taverna.server.master.notification;
+/*
+ * 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.
+ */

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/package-info.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/package-info.java
new file mode 100644
index 0000000..d912ac8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/package-info.java
@@ -0,0 +1,24 @@
+/*
+ */
+/**
+ * The core of the implementation of Taverna Server, including the
+ * implementations of the SOAP and REST interfaces.
+ */
+package org.taverna.server.master;
+/*
+ * 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.
+ */
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ContentTypes.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ContentTypes.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ContentTypes.java
new file mode 100644
index 0000000..d9aef82
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ContentTypes.java
@@ -0,0 +1,41 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.MediaType.APPLICATION_ATOM_XML;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+
+/**
+ * Miscellaneous content type constants.
+ * 
+ * @author Donal Fellows
+ */
+interface ContentTypes {
+	static final String URI_LIST = "text/uri-list";
+	static final String ZIP = "application/zip";
+	static final String TEXT = TEXT_PLAIN;
+	static final String XML = APPLICATION_XML;
+	static final String JSON = APPLICATION_JSON;
+	static final String BYTES = APPLICATION_OCTET_STREAM;
+	static final String ATOM = APPLICATION_ATOM_XML;
+	static final String ROBUNDLE = "application/vnd.wf4ever.robundle+zip";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/DirectoryContents.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/DirectoryContents.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/DirectoryContents.java
new file mode 100644
index 0000000..42d4b0e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/DirectoryContents.java
@@ -0,0 +1,74 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static org.taverna.server.master.common.Uri.secure;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.common.DirEntryReference;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+
+/**
+ * The result of a RESTful operation to list the contents of a directory. Done
+ * with JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement
+@XmlType(name = "DirectoryContents")
+@XmlSeeAlso(MakeOrUpdateDirEntry.class)
+public class DirectoryContents {
+	/**
+	 * The contents of the directory.
+	 */
+	@XmlElementRef
+	public List<DirEntryReference> contents;
+
+	/**
+	 * Make an empty directory description. Required for JAXB.
+	 */
+	public DirectoryContents() {
+		contents = new ArrayList<>();
+	}
+
+	/**
+	 * Make a directory description.
+	 * 
+	 * @param ui
+	 *            The factory for URIs.
+	 * @param collection
+	 *            The real directory contents that we are to describe.
+	 */
+	public DirectoryContents(UriInfo ui, Collection<DirectoryEntry> collection) {
+		contents = new ArrayList<>();
+		UriBuilder ub = secure(ui).path("{filename}");
+		for (DirectoryEntry e : collection)
+			contents.add(DirEntryReference.newInstance(ub, e));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/FileSegment.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/FileSegment.java b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/FileSegment.java
new file mode 100644
index 0000000..6b7aaff
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/FileSegment.java
@@ -0,0 +1,91 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * 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.
+ */
+
+import static javax.ws.rs.core.Response.ok;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * Representation of a segment of a file to be read by JAX-RS.
+ * 
+ * @author Donal Fellows
+ */
+public class FileSegment {
+	/** The file to read a segment of. */
+	public final File file;
+	/** The offset of the first byte of the segment to read. */
+	public Integer from;
+	/** The offset of the first byte after the segment to read. */
+	public Integer to;
+
+	/**
+	 * Parse the HTTP Range header and determine what exact range of the file to
+	 * read.
+	 * 
+	 * @param f
+	 *            The file this refers to
+	 * @param range
+	 *            The content of the Range header.
+	 * @throws FilesystemAccessException
+	 *             If we can't determine the length of the file (shouldn't
+	 *             happen).
+	 */
+	public FileSegment(File f, String range) throws FilesystemAccessException {
+		file = f;
+		Matcher m = Pattern.compile("^\\s*bytes=(\\d*)-(\\d*)\\s*$").matcher(
+				range);
+		if (m.matches()) {
+			if (!m.group(1).isEmpty())
+				from = Integer.valueOf(m.group(1));
+			if (!m.group(2).isEmpty())
+				to = Integer.valueOf(m.group(2)) + 1;
+			int size = (int) f.getSize();
+			if (from == null) {
+				from = size - to;
+				to = size;
+			} else if (to == null)
+				to = size;
+			else if (to > size)
+				to = size;
+		}
+	}
+
+	/**
+	 * Convert to a response, as per RFC 2616.
+	 * 
+	 * @param type
+	 *            The expected type of the data.
+	 * @return A JAX-RS response.
+	 */
+	public Response toResponse(MediaType type) {
+		if (from == null && to == null)
+			return ok(file).type(type).build();
+		if (from >= to)
+			return ok("Requested range not satisfiable").status(416).build();
+		return ok(this).status(206).type(type).build();
+	}
+}
\ No newline at end of file