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
-               
-       }
-}


Reply via email to