You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/23 16:37:02 UTC
[02/49] incubator-taverna-server git commit: taverna-* module names
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/misc/xsd/persistence_1_0.xsd
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/misc/xsd/persistence_1_0.xsd b/taverna-server-webapp/src/misc/xsd/persistence_1_0.xsd
new file mode 100644
index 0000000..a485e30
--- /dev/null
+++ b/taverna-server-webapp/src/misc/xsd/persistence_1_0.xsd
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- persistence.xml schema -->
+<xsd:schema targetNamespace="http://java.sun.com/xml/ns/persistence"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:persistence="http://java.sun.com/xml/ns/persistence"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ version="1.0">
+
+ <xsd:annotation>
+ <xsd:documentation>
+ @(#)persistence_1_0.xsd 1.0 Feb 9 2006
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:annotation>
+ <xsd:documentation>
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2005-2007 Sun Microsystems, Inc. All rights reserved.
+
+ The contents of this file are subject to the terms of either the
+ GNU General Public License Version 2 only ("GPL") or the Common
+ Development and Distribution License("CDDL") (collectively, the
+ "License"). You may not use this file except in compliance with
+ the License. You can obtain a copy of the License at
+ https://glassfish.dev.java.net/public/CDDL+GPL.html or
+ glassfish/bootstrap/legal/LICENSE.txt. See the License for the
+ specific language governing permissions and limitations under the
+ License.
+
+ When distributing the software, include this License Header
+ Notice in each file and include the License file at
+ glassfish/bootstrap/legal/LICENSE.txt. Sun designates this
+ particular file as subject to the "Classpath" exception as
+ provided by Sun in the GPL Version 2 section of the License file
+ that accompanied this code. If applicable, add the following
+ below the License Header, with the fields enclosed by brackets []
+ replaced by your own identifying information:
+ "Portions Copyrighted [year] [name of copyright owner]"
+
+ Contributor(s):
+
+ If you wish your version of this file to be governed by only the
+ CDDL or only the GPL Version 2, indicate your decision by adding
+ "[Contributor] elects to include this software in this
+ distribution under the [CDDL or GPL Version 2] license." If you
+ don't indicate a single choice of license, a recipient has the
+ option to distribute your version of this file under either the
+ CDDL, the GPL Version 2 or to extend the choice of license to its
+ licensees as provided above. However, if you add GPL Version 2
+ code and therefore, elected the GPL Version 2 license, then the
+ option applies only if the new code is made subject to such
+ option by the copyright holder.
+
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:annotation>
+ <xsd:documentation><![CDATA[
+
+ This is the XML Schema for the persistence configuration file.
+ The file must be named "META-INF/persistence.xml" in the
+ persistence archive.
+ Persistence configuration files must indicate
+ the persistence schema by using the persistence namespace:
+
+ http://java.sun.com/xml/ns/persistence
+
+ and indicate the version of the schema by
+ using the version element as shown below:
+
+ <persistence xmlns="http://java.sun.com/xml/ns/persistence"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
+ http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
+ version="1.0">
+ ...
+ </persistence>
+
+ ]]></xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:simpleType name="versionType">
+ <xsd:restriction base="xsd:token">
+ <xsd:pattern value="[0-9]+(\.[0-9]+)*"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="persistence">
+ <xsd:complexType>
+ <xsd:sequence>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="persistence-unit"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+
+ Configuration of a persistence unit.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="description" type="xsd:string"
+ minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ Textual description of this persistence unit.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="provider" type="xsd:string"
+ minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ Provider class that supplies EntityManagers for this
+ persistence unit.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="jta-data-source" type="xsd:string"
+ minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ The container-specific name of the JTA datasource to use.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="non-jta-data-source" type="xsd:string"
+ minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ The container-specific name of a non-JTA datasource to use.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="mapping-file" type="xsd:string"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ File containing mapping information. Loaded as a resource
+ by the persistence provider.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="jar-file" type="xsd:string"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ Jar file that should be scanned for entities.
+ Not applicable to Java SE persistence units.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="class" type="xsd:string"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ Class to scan for annotations. It should be annotated
+ with either @Entity, @Embeddable or @MappedSuperclass.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="exclude-unlisted-classes" type="xsd:boolean"
+ default="false" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ When set to true then only listed classes and jars will
+ be scanned for persistent classes, otherwise the enclosing
+ jar or directory will also be scanned. Not applicable to
+ Java SE persistence units.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+
+ <!-- **************************************************** -->
+
+ <xsd:element name="properties" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ A list of vendor-specific properties.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="property"
+ minOccurs="0" maxOccurs="unbounded">
+ <xsd:annotation>
+ <xsd:documentation>
+ A name-value pair.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:attribute name="name" type="xsd:string"
+ use="required"/>
+ <xsd:attribute name="value" type="xsd:string"
+ use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ </xsd:sequence>
+
+ <!-- **************************************************** -->
+
+ <xsd:attribute name="name" type="xsd:string" use="required">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ Name used in code to reference this persistence unit.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+
+ <!-- **************************************************** -->
+
+ <xsd:attribute name="transaction-type"
+ type="persistence:persistence-unit-transaction-type">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ Type of transactions used by EntityManagers from this
+ persistence unit.
+
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="version" type="persistence:versionType"
+ fixed="1.0" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- **************************************************** -->
+
+ <xsd:simpleType name="persistence-unit-transaction-type">
+ <xsd:annotation>
+ <xsd:documentation>
+
+ public enum TransactionType { JTA, RESOURCE_LOCAL };
+
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:token">
+ <xsd:enumeration value="JTA"/>
+ <xsd:enumeration value="RESOURCE_LOCAL"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
+
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/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
new file mode 100644
index 0000000..79c026b
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ *
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+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/2c71f9a9/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
new file mode 100644
index 0000000..9665cf0
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
@@ -0,0 +1,246 @@
+package org.taverna.server.master;
+
+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/2c71f9a9/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
new file mode 100644
index 0000000..0450317
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
@@ -0,0 +1,68 @@
+package org.taverna.server.master;
+
+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/2c71f9a9/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
new file mode 100644
index 0000000..a2a0791
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ *
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.mocks;
+
+import static java.util.Calendar.MINUTE;
+import static java.util.Collections.unmodifiableList;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.common.Status.Initialized;
+
+import 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/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
new file mode 100644
index 0000000..81dd08c
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
@@ -0,0 +1,59 @@
+package org.taverna.server.master.mocks;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+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/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
new file mode 100644
index 0000000..d864214
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
@@ -0,0 +1,64 @@
+package org.taverna.server.master.mocks;
+
+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/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
new file mode 100644
index 0000000..a3751e4
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
@@ -0,0 +1,151 @@
+package org.taverna.server.master.mocks;
+
+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/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
new file mode 100644
index 0000000..1a68d2c
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
@@ -0,0 +1,110 @@
+package org.taverna.server.master.mocks;
+
+import java.net.URI;
+import java.util.List;
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * 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/2c71f9a9/taverna-server-webapp/src/test/resources/example.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/resources/example.xml b/taverna-server-webapp/src/test/resources/example.xml
new file mode 100644
index 0000000..14cc242
--- /dev/null
+++ b/taverna-server-webapp/src/test/resources/example.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
+
+ <bean id="policy" class="org.taverna.server.master.mocks.SimpleServerPolicy"
+ lazy-init="false" scope="singleton">
+ <property name="maxRuns" value="1">
+ <description>
+ Limit on total number of simultaneous runs.
+ </description>
+ </property>
+ <property name="cleanerInterval" value="300">
+ <description>
+ Time between trying to delete expired runs, in seconds.
+ </description>
+ </property>
+ </bean>
+
+ <bean id="runFactory" class="org.taverna.server.master.mocks.ExampleRun$Builder">
+ <constructor-arg type="int" value="10" /> <!-- "initialLifetimeMinutes" -->
+ </bean>
+
+ <bean id="runCatalog" scope="singleton"
+ class="org.taverna.server.master.mocks.SimpleNonpersistentRunStore">
+ <property name="policy" ref="policy" />
+ </bean>
+
+ <bean id="listenerFactory" class="org.taverna.server.master.mocks.SimpleListenerFactory">
+ <property name="builders">
+ <description>
+ This map describes how to build each type of supported
+ event listener that is not installed by default. Any site policy for
+ a listeners should be installed using its properties, as shown. The
+ "key" is the type, the "class" is the builder for actual instances
+ (which must be an instance of
+ org.taverna.server.master.factories.SimpleListenerFactory.Builder)
+ and any policies and installation-specific configurations are
+ characterised by properties such as "sitePolicy" below.
+ </description>
+ <map>
+ <!-- <entry key="exampleListener">-->
+ <!--
+ <bean
+ class="org.taverna.server.master.example.ExampleListener$Builder">
+ -->
+ <!-- <property name="sitePolicy">-->
+ <!-- <value>Just an example!</value>-->
+ <!-- </property>-->
+ <!-- </bean>-->
+ <!-- </entry>-->
+ </map>
+ </property>
+ </bean>
+</beans>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/resources/log4j.properties b/taverna-server-webapp/src/test/resources/log4j.properties
new file mode 100644
index 0000000..6707f55
--- /dev/null
+++ b/taverna-server-webapp/src/test/resources/log4j.properties
@@ -0,0 +1,4 @@
+log4j.rootLogger=info, R
+log4j.appender.R=org.apache.log4j.ConsoleAppender
+log4j.appender.R.layout=org.apache.log4j.PatternLayout
+log4j.appender.R.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} %C{1} - %m%n
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-worker/pom.xml b/taverna-server-worker/pom.xml
new file mode 100644
index 0000000..8006c6d
--- /dev/null
+++ b/taverna-server-worker/pom.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.taverna.server</groupId>
+ <artifactId>taverna-server</artifactId>
+ <version>3.1.0-incubating-SNAPSHOT</version>
+ </parent>
+ <artifactId>taverna-server-worker</artifactId>
+ <name>Apache Taverna Server Workflow Executor/File System Access Process Implementation</name>
+ <description>This is the implementation of the factory process that is started up by the web application to manage executing Taverna Workflow executeworkflow.sh calls. Also provides per-user access to filestore.</description>
+
+ <properties>
+ <workerMainClass>org.taverna.server.localworker.impl.TavernaRunManager</workerMainClass>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-server-runinterface</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-server-usagerecord</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.taverna.language</groupId>
+ <artifactId>taverna-scufl2-api</artifactId>
+ <version>${taverna.language.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.taverna.language</groupId>
+ <artifactId>taverna-scufl2-t2flow</artifactId>
+ <version>${taverna.language.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.taverna.language</groupId>
+ <artifactId>taverna-scufl2-wfbundle</artifactId>
+ <version>${taverna.language.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ <archive>
+ <manifest>
+ <mainClass>${workerMainClass}</mainClass>
+ </manifest>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <versionRange>[2.0,)</versionRange>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <execute />
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/META-INF/MANIFEST.MF b/taverna-server-worker/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5e94951
--- /dev/null
+++ b/taverna-server-worker/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
new file mode 100644
index 0000000..600913a
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ *
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.api;
+
+import static java.nio.charset.Charset.defaultCharset;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * The defaults associated with this worker, together with various other
+ * constants.
+ *
+ * @author Donal Fellows
+ */
+public abstract class Constants {
+ /**
+ * Subdirectories of the working directory to create by default.
+ */
+ public static final String[] SUBDIR_LIST = { "conf", "externaltool", "feed",
+ "interactions", "lib", "logs", "plugins", "repository", "var" };
+
+ /** The name of the default encoding for characters on this machine. */
+ public static final String SYSTEM_ENCODING = defaultCharset().name();
+
+ /**
+ * Password to use to encrypt security information. This default is <7 chars
+ * to work even without Unlimited Strength JCE.
+ */
+ public static final char[] KEYSTORE_PASSWORD = { 'c', 'h', 'a', 'n', 'g', 'e' };
+
+ /**
+ * The name of the directory (in the home directory) where security settings
+ * will be written.
+ */
+ public static final String SECURITY_DIR_NAME = ".taverna-server-security";
+
+ /** The name of the file that will be the created keystore. */
+ public static final String KEYSTORE_FILE = "t2keystore.ubr";
+
+ /** The name of the file that will be the created truststore. */
+ public static final String TRUSTSTORE_FILE = "t2truststore.ubr";
+
+ /**
+ * The name of the file that contains the password to unlock the keystore
+ * and truststore.
+ */
+ public static final String PASSWORD_FILE = "password.txt";
+
+ // --------- UNUSED ---------
+ // /**
+ // * The name of the file that contains the mapping from URIs to keystore
+ // * aliases.
+ // */
+ // public static final String URI_ALIAS_MAP = "urlmap.txt";
+
+ /**
+ * Used to instruct the Taverna credential manager to use a non-default
+ * location for user credentials.
+ */
+ public static final String CREDENTIAL_MANAGER_DIRECTORY = "-cmdir";
+
+ /**
+ * Used to instruct the Taverna credential manager to take its master
+ * password from standard input.
+ */
+ public static final String CREDENTIAL_MANAGER_PASSWORD = "-cmpassword";
+
+ /**
+ * Name of environment variable used to pass HELIO security tokens to
+ * workflows.
+ */
+ // This technique is known to be insecure; bite me.
+ public static final String HELIO_TOKEN_NAME = "HELIO_CIS_TOKEN";
+
+ /**
+ * The name of the standard listener, which is installed by default.
+ */
+ public static final String DEFAULT_LISTENER_NAME = "io";
+
+ /**
+ * Time to wait for the subprocess to wait, in milliseconds.
+ */
+ public static final int START_WAIT_TIME = 1500;
+
+ /**
+ * Time to wait for success or failure of a death-causing activity (i.e.,
+ * sending a signal).
+ */
+ public static final int DEATH_TIME = 333;
+
+ /**
+ * The name of the file (in this code's resources) that provides the default
+ * security policy that we use.
+ */
+ public static final String SECURITY_POLICY_FILE = "security.policy";
+
+ /**
+ * The Java property holding security policy info.
+ */
+ public static final String SEC_POLICY_PROP = "java.security.policy";
+ /**
+ * The Java property to set to make this code not try to enforce security
+ * policy.
+ */
+ public static final String UNSECURE_PROP = "taverna.suppressrestrictions.rmi";
+ /**
+ * The Java property that holds the name of the host name to enforce.
+ */
+ public static final String RMI_HOST_PROP = "java.rmi.server.hostname";
+ /**
+ * The default hostname to require in secure mode. This is the
+ * <i>resolved</i> version of "localhost".
+ */
+ public static final String LOCALHOST;
+ static {
+ String h = "127.0.0.1"; // fallback
+ try {
+ h = InetAddress.getByName("localhost").getHostAddress();
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ } finally {
+ LOCALHOST = h;
+ }
+ }
+
+ /**
+ * Time to wait during closing down this process. In milliseconds.
+ */
+ public static final int DEATH_DELAY = 500;
+ /**
+ * The name of the property describing where shared directories should be
+ * located.
+ */
+ public static final String SHARED_DIR_PROP = "taverna.sharedDirectory";
+
+ public static final String TIME = "/usr/bin/time";
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
new file mode 100644
index 0000000..3896c06
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ *
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.api;
+
+/**
+ *
+ * @author Donal Fellows
+ */
+public interface RunAccounting {
+ /**
+ * Logs that a run has started executing.
+ */
+ void runStarted();
+
+ /**
+ * Logs that a run has finished executing.
+ */
+ void runCeased();
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
new file mode 100644
index 0000000..c513ed8
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ *
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.api;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import org.taverna.server.localworker.impl.LocalWorker;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+/**
+ * The interface between the connectivity layer and the thunk to the
+ * subprocesses.
+ *
+ * @author Donal Fellows
+ */
+public interface Worker {
+ /**
+ * Fire up the workflow. This causes a transition into the operating state.
+ *
+ * @param local
+ * The reference to the factory class for this worker.
+ * @param executeWorkflowCommand
+ * The command to run to execute the workflow.
+ * @param workflow
+ * The workflow document to execute.
+ * @param workingDir
+ * What directory to use as the working directory.
+ * @param inputBaclavaFile
+ * The baclava file to use for inputs, or <tt>null</tt> to use
+ * the other <b>input*</b> arguments' values.
+ * @param inputRealFiles
+ * A mapping of input names to files that supply them. Note that
+ * we assume that nothing mapped here will be mapped in
+ * <b>inputValues</b>.
+ * @param inputValues
+ * A mapping of input names to values to supply to them. Note
+ * that we assume that nothing mapped here will be mapped in
+ * <b>inputFiles</b>.
+ * @param inputDelimiters
+ * A mapping of input names to characters used to split them into
+ * lists.
+ * @param outputBaclavaFile
+ * What baclava file to write the output from the workflow into,
+ * or <tt>null</tt> to have it written into the <tt>out</tt>
+ * subdirectory.
+ * @param contextDirectory
+ * The directory containing the keystore and truststore. <i>Must
+ * not be <tt>null</tt>.</i>
+ * @param keystorePassword
+ * The password to the keystore and truststore. <i>Must not be
+ * <tt>null</tt>.</i>
+ * @param generateProvenance
+ * Whether to generate a run bundle containing provenance data.
+ * @param environment
+ * Any environment variables that need to be added to the
+ * invokation.
+ * @param masterToken
+ * The internal name of the workflow run.
+ * @param runtimeSettings
+ * List of configuration details for the forked runtime.
+ * @return Whether a successful start happened.
+ * @throws Exception
+ * If any of quite a large number of things goes wrong.
+ */
+ boolean initWorker(LocalWorker local, String executeWorkflowCommand,
+ byte[] workflow, File workingDir, File inputBaclavaFile,
+ Map<String, File> inputRealFiles, Map<String, String> inputValues,
+ Map<String, String> inputDelimiters, File outputBaclavaFile,
+ File contextDirectory, char[] keystorePassword,
+ boolean generateProvenance, Map<String, String> environment,
+ String masterToken, List<String> runtimeSettings) throws Exception;
+
+ /**
+ * Kills off the subprocess if it exists and is alive.
+ *
+ * @throws Exception
+ * if anything goes badly wrong when the worker is being killed
+ * off.
+ */
+ void killWorker() throws Exception;
+
+ /**
+ * Move the worker out of the stopped state and back to operating.
+ *
+ * @throws Exception
+ * if it fails (which it always does; operation currently
+ * unsupported).
+ */
+ void startWorker() throws Exception;
+
+ /**
+ * Move the worker into the stopped state from the operating state.
+ *
+ * @throws Exception
+ * if it fails (which it always does; operation currently
+ * unsupported).
+ */
+ void stopWorker() throws Exception;
+
+ /**
+ * @return The status of the workflow run. Note that this can be an
+ * expensive operation.
+ */
+ RemoteStatus getWorkerStatus();
+
+ /**
+ * @return The listener that is registered by default, in addition to all
+ * those that are explicitly registered by the user.
+ */
+ RemoteListener getDefaultListener();
+
+ /**
+ * @param receiver
+ * The destination where any final usage records are to be
+ * written in order to log them back to the server.
+ */
+ void setURReceiver(UsageRecordReceiver receiver);
+
+ /**
+ * Arrange for the deletion of any resources created during worker process
+ * construction. Guaranteed to be the last thing done before finalization.
+ *
+ * @throws ImplementationException
+ * If anything goes wrong.
+ */
+ void deleteLocalResources() throws ImplementationException;
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
new file mode 100644
index 0000000..4ce13a7
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
@@ -0,0 +1,18 @@
+package org.taverna.server.localworker.api;
+
+
+/**
+ * Class that manufactures instances of {@link Worker}.
+ *
+ * @author Donal Fellows
+ */
+public interface WorkerFactory {
+ /**
+ * Create an instance of the low-level worker class.
+ *
+ * @return The worker object.
+ * @throws Exception
+ * If anything goes wrong.
+ */
+ Worker makeInstance() throws Exception;
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
new file mode 100644
index 0000000..1692856
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ *
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.impl;
+
+import static org.apache.commons.io.FileUtils.forceDelete;
+import static org.apache.commons.io.FileUtils.forceMkdir;
+import static org.apache.commons.io.FileUtils.touch;
+import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedNewFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.collections.MapIterator;
+import org.apache.commons.collections.map.ReferenceMap;
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
+import org.taverna.server.localworker.remote.RemoteFile;
+
+/**
+ * This class acts as a remote-aware delegate for the workflow run's working
+ * directory and its subdirectories.
+ *
+ * @author Donal Fellows
+ * @see FileDelegate
+ */
+@SuppressWarnings("serial")
+public class DirectoryDelegate extends UnicastRemoteObject implements
+ RemoteDirectory {
+ private File dir;
+ private DirectoryDelegate parent;
+ private ReferenceMap localCache;
+
+ /**
+ * @param dir
+ * @param parent
+ * @throws RemoteException
+ * If registration of the directory fails.
+ */
+ public DirectoryDelegate(@Nonnull File dir,
+ @Nonnull DirectoryDelegate parent) throws RemoteException {
+ super();
+ this.localCache = new ReferenceMap();
+ this.dir = dir;
+ this.parent = parent;
+ }
+
+ @Override
+ public Collection<RemoteDirectoryEntry> getContents()
+ throws RemoteException {
+ List<RemoteDirectoryEntry> result = new ArrayList<>();
+ for (String s : dir.list()) {
+ if (s.equals(".") || s.equals(".."))
+ continue;
+ File f = new File(dir, s);
+ RemoteDirectoryEntry entry;
+ synchronized (localCache) {
+ entry = (RemoteDirectoryEntry) localCache.get(s);
+ if (f.isDirectory()) {
+ if (entry == null || !(entry instanceof DirectoryDelegate)) {
+ entry = new DirectoryDelegate(f, this);
+ localCache.put(s, entry);
+ }
+ } else if (f.isFile()) {
+ if (entry == null || !(entry instanceof FileDelegate)) {
+ entry = new FileDelegate(f, this);
+ localCache.put(s, entry);
+ }
+ } else {
+ // not file or dir; skip...
+ continue;
+ }
+ }
+ result.add(entry);
+ }
+ return result;
+ }
+
+ @Override
+ public RemoteFile makeEmptyFile(String name) throws IOException {
+ File f = getValidatedNewFile(dir, name);
+ touch(f);
+ FileDelegate delegate = new FileDelegate(f, this);
+ synchronized (localCache) {
+ localCache.put(name, delegate);
+ }
+ return delegate;
+ }
+
+ @Override
+ public RemoteDirectory makeSubdirectory(String name) throws IOException {
+ File f = getValidatedNewFile(dir, name);
+ forceMkdir(f);
+ DirectoryDelegate delegate = new DirectoryDelegate(f, this);
+ synchronized (localCache) {
+ localCache.put(name, delegate);
+ }
+ return delegate;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void destroy() throws IOException {
+ if (parent == null)
+ throw new IOException("tried to destroy main job working directory");
+ Collection<RemoteDirectoryEntry> values;
+ synchronized (localCache) {
+ values = new ArrayList<>(localCache.values());
+ }
+ for (RemoteDirectoryEntry obj : values) {
+ if (obj == null)
+ continue;
+ try {
+ obj.destroy();
+ } catch (IOException e) {
+ }
+ }
+ forceDelete(dir);
+ parent.forgetEntry(this);
+ }
+
+ @Override
+ public RemoteDirectory getContainingDirectory() {
+ return parent;
+ }
+
+ void forgetEntry(@Nonnull RemoteDirectoryEntry entry) {
+ synchronized (localCache) {
+ MapIterator i = localCache.mapIterator();
+ while (i.hasNext()) {
+ Object key = i.next();
+ if (entry == i.getValue()) {
+ localCache.remove(key);
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public String getName() {
+ if (parent == null)
+ return "";
+ return dir.getName();
+ }
+
+ @Override
+ public Date getModificationDate() throws RemoteException {
+ return new Date(dir.lastModified());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
new file mode 100644
index 0000000..7e47af9
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ *
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.impl;
+
+import static java.lang.System.arraycopy;
+import static java.net.InetAddress.getLocalHost;
+import static org.apache.commons.io.FileUtils.copyFile;
+import static org.apache.commons.io.FileUtils.forceDelete;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Date;
+
+import javax.annotation.Nonnull;
+
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteFile;
+
+/**
+ * This class acts as a remote-aware delegate for the files in a workflow run's
+ * working directory and its subdirectories.
+ *
+ * @author Donal Fellows
+ * @see DirectoryDelegate
+ */
+@java.lang.SuppressWarnings("serial")
+public class FileDelegate extends UnicastRemoteObject implements RemoteFile {
+ private File file;
+ private DirectoryDelegate parent;
+
+ /**
+ * @param file
+ * @param parent
+ * @throws RemoteException
+ * If registration of the file fails.
+ */
+ public FileDelegate(@Nonnull File file, @Nonnull DirectoryDelegate parent)
+ throws RemoteException {
+ super();
+ this.file = file;
+ this.parent = parent;
+ }
+
+ @Override
+ public byte[] getContents(int offset, int length) throws IOException {
+ if (length == -1)
+ length = (int) (file.length() - offset);
+ if (length < 0 || length > 1024 * 64)
+ length = 1024 * 64;
+ byte[] buffer = new byte[length];
+ int read;
+ try (FileInputStream fis = new FileInputStream(file)) {
+ if (offset > 0 && fis.skip(offset) != offset)
+ throw new IOException("did not move to correct offset in file");
+ read = fis.read(buffer);
+ }
+ if (read <= 0)
+ return new byte[0];
+ if (read < buffer.length) {
+ byte[] shortened = new byte[read];
+ arraycopy(buffer, 0, shortened, 0, read);
+ return shortened;
+ }
+ return buffer;
+ }
+
+ @Override
+ public long getSize() {
+ return file.length();
+ }
+
+ @Override
+ public void setContents(byte[] data) throws IOException {
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(data);
+ }
+ }
+
+ @Override
+ public void appendContents(byte[] data) throws IOException {
+ try (FileOutputStream fos = new FileOutputStream(file, true)) {
+ fos.write(data);
+ }
+ }
+
+ @Override
+ public void destroy() throws IOException {
+ forceDelete(file);
+ parent.forgetEntry(this);
+ parent = null;
+ }
+
+ @Override
+ public RemoteDirectory getContainingDirectory() {
+ return parent;
+ }
+
+ @Override
+ public String getName() {
+ return file.getName();
+ }
+
+ @Override
+ public void copy(RemoteFile sourceFile) throws RemoteException, IOException {
+ String sourceHost = sourceFile.getNativeHost();
+ if (!getNativeHost().equals(sourceHost)) {
+ throw new IOException(
+ "cross-system copy not implemented; cannot copy from "
+ + sourceHost + " to " + getNativeHost());
+ }
+ // Must copy; cannot count on other file to stay unmodified
+ copyFile(new File(sourceFile.getNativeName()), file);
+ }
+
+ @Override
+ public String getNativeName() {
+ return file.getAbsolutePath();
+ }
+
+ @Override
+ public String getNativeHost() {
+ try {
+ return getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ throw new RuntimeException(
+ "unexpected failure to resolve local host address", e);
+ }
+ }
+
+ @Override
+ public Date getModificationDate() throws RemoteException {
+ return new Date(file.lastModified());
+ }
+}