http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-execution-delegate/src/test/java/SerializationTest.java ---------------------------------------------------------------------- diff --git a/taverna-server-execution-delegate/src/test/java/SerializationTest.java b/taverna-server-execution-delegate/src/test/java/SerializationTest.java new file mode 100644 index 0000000..c4bf0b9 --- /dev/null +++ b/taverna-server-execution-delegate/src/test/java/SerializationTest.java @@ -0,0 +1,54 @@ +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.io.StringWriter; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.SchemaOutputResolver; +import javax.xml.transform.Result; +import javax.xml.transform.stream.StreamResult; + +import org.junit.Before; +import org.junit.Test; +import org.taverna.server.execution_delegate.RemoteExecution.WorkflowReportDocument; + +public class SerializationTest { + private static final boolean PRINT = true; + SchemaOutputResolver sink; + StringWriter schema; + + String schema() { + return schema.toString(); + } + + @Before + public void init() { + schema = new StringWriter(); + sink = new SchemaOutputResolver() { + @Override + public Result createOutput(String namespaceUri, + String suggestedFileName) throws IOException { + StreamResult sr = new StreamResult(schema); + sr.setSystemId("/dev/null"); + return sr; + } + }; + assertEquals("", schema()); + } + + @Test + public void testSchemaGeneration() throws JAXBException, IOException { + JAXBContext.newInstance(WorkflowReportDocument.class).generateSchema( + sink); + assertFalse("generated schema must be non-empty", schema().isEmpty()); + assertTrue( + "generated schema must define workflowReport element", + schema().contains( + "<xs:element name=\"workflowReport\" type=\"WorkflowReport\"/>\n")); + if (PRINT) + System.out.print(schema()); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/.gitignore ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/.gitignore b/taverna-server-port-description/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/taverna-server-port-description/.gitignore @@ -0,0 +1 @@ +/target http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/pom.xml b/taverna-server-port-description/pom.xml new file mode 100644 index 0000000..99582ed --- /dev/null +++ b/taverna-server-port-description/pom.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.taverna.server</groupId> + <artifactId>taverna-server</artifactId> + <version>3.1.0-incubating-SNAPSHOT</version> + </parent> + <artifactId>taverna-server-port-description</artifactId> + <name>Apache Taverna Server Workflow Port Descriptor Types</name> + <description>The structural types used to describe ports on workflows, as exported by Taverna Server.</description> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <build> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-eclipse-plugin</artifactId> + <configuration> + <projectNameTemplate>[artifactId]-[version]</projectNameTemplate> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> +</project> http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java new file mode 100644 index 0000000..2ea392f --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2010 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +import javax.xml.bind.annotation.XmlType; + +@XmlType(name = "AbsentValue") +public class AbsentValue extends AbstractValue { + +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java new file mode 100644 index 0000000..e57c4f9 --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2011-2012 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlID; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import org.taverna.server.port_description.utils.IntAdapter; + +@XmlType(name = "Port") +public class AbstractPort { + @XmlID + @XmlAttribute(required = true) + public String name; + + @XmlAttribute + @XmlSchemaType(name = "int") + @XmlJavaTypeAdapter(IntAdapter.class) + public Integer depth; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java new file mode 100644 index 0000000..7c3fe9a --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +import java.net.URI; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + +@XmlType(name = "PortDescription") +public abstract class AbstractPortDescription { + @XmlAttribute + public String workflowId; + @XmlAttribute + @XmlSchemaType(name = "anyURI") + public URI workflowRun; + @XmlAttribute + public String workflowRunId; + + public void fillInBaseData(String docId, String runId, URI runUrl) { + this.workflowId = docId; + this.workflowRun = runUrl; + this.workflowRunId = runId; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java new file mode 100644 index 0000000..47232c2 --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +import static org.taverna.server.port_description.Namespaces.XLINK; + +import java.net.URI; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.bind.annotation.XmlType; + +@XmlType(name = "Value") +@XmlSeeAlso( { ErrorValue.class, LeafValue.class, ListValue.class, AbsentValue.class }) +public abstract class AbstractValue { + @XmlAttribute(namespace = XLINK) + @XmlSchemaType(name = "anyURI") + public URI href; + + public void setAddress(URI uri, String localAddress) { + if (uri.getPath().endsWith("/")) { + href = URI.create(uri + "wd/out/" + localAddress); + } else { + href = URI.create(uri + "/wd/out/" + localAddress); + } + //about = "out/" + localAddress; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java new file mode 100644 index 0000000..0bb07b4 --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import org.taverna.server.port_description.utils.IntAdapter; + +@XmlType(name = "ErrorValue") +public class ErrorValue extends AbstractValue { + @XmlAttribute + @XmlSchemaType(name = "int") + @XmlJavaTypeAdapter(IntAdapter.class) + public Integer depth; + @XmlAttribute(name = "errorFile") + public String fileName; + @XmlAttribute(name = "errorByteLength") + public Long byteLength; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java new file mode 100644 index 0000000..60b9353 --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +import static org.taverna.server.port_description.Namespaces.XLINK; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + +/** + * A description of the inputs of a workflow run, as they are currently known + * about. + * + * @author Donal Fellows. + */ +@XmlRootElement +public class InputDescription extends AbstractPortDescription { + @XmlElement + public List<InputPort> input = new ArrayList<>(); + + @XmlType(name = "InputPort") + public static class InputPort extends AbstractPort { + @XmlAttribute(namespace = XLINK) + @XmlSchemaType(name = "anyURI") + public URI href; + } + + /** + * Add an input port to the list of ports. + * + * @param name + * The name of the port to add. + * @return The port (so that its details may be set); + */ + public InputPort addPort(String name) { + InputPort p = new InputPort(); + p.name = name; + input.add(p); + return p; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java new file mode 100644 index 0000000..052c0ef --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlType; + +@XmlType(name = "LeafValue") +public class LeafValue extends AbstractValue { + @XmlAttribute(name = "contentFile") + public String fileName; + @XmlAttribute(name = "contentType") + public String contentType; + @XmlAttribute(name = "contentByteLength") + public Long byteLength; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java new file mode 100644 index 0000000..b14cdf1 --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; + +import org.taverna.server.port_description.utils.IntAdapter; + +@XmlType(name = "ListValue") +public class ListValue extends AbstractValue { + @XmlAttribute + @XmlSchemaType(name = "int") + @XmlJavaTypeAdapter(IntAdapter.class) + public Integer length; + @XmlElements({ + @XmlElement(name = "value", type = LeafValue.class, nillable = false), + @XmlElement(name = "list", type = ListValue.class, nillable = false), + @XmlElement(name = "error", type = ErrorValue.class, nillable = false), + @XmlElement(name = "absent", type = AbsentValue.class, nillable = false) }) + public List<AbstractValue> contents = new ArrayList<>(); +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java new file mode 100644 index 0000000..4003cdb --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +public interface Namespaces { + static final String DATA = "http://ns.taverna.org.uk/2010/port/"; + static final String RUN = "http://ns.taverna.org.uk/2010/run/"; + static final String XLINK = "http://www.w3.org/1999/xlink"; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java new file mode 100644 index 0000000..0b94973 --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + +/** + * A description of the outputs of a workflow run, as they are currently known + * about. + * + * @author Donal Fellows + */ +@XmlRootElement(name = "workflowOutputs") +public class OutputDescription extends AbstractPortDescription { + private static final AbsentValue ABSENT_VALUE = new AbsentValue(); + @XmlElement(name = "output") + public List<OutputPort> ports = new ArrayList<>(); + + @XmlType(name = "OutputPort") + public static class OutputPort extends AbstractPort { + @XmlElements({ + @XmlElement(name = "value", type = LeafValue.class, nillable = false, required = true), + @XmlElement(name = "list", type = ListValue.class, nillable = false, required = true), + @XmlElement(name = "error", type = ErrorValue.class, nillable = false, required = true), + @XmlElement(name = "absent", type = AbsentValue.class, nillable = false, required = true) }) + public AbstractValue output; + } + + /** + * Add an output port to the list of ports. + * + * @param name + * The name of the port to add. + * @return The port (so that its value may be set); + */ + public OutputPort addPort(String name) { + OutputPort p = new OutputPort(); + p.name = name; + p.output = ABSENT_VALUE; + ports.add(p); + return p; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java new file mode 100644 index 0000000..b1ac2c6 --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +@XmlSchema(namespace = DATA, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = { + @XmlNs(prefix = "port", namespaceURI = DATA), + @XmlNs(prefix = "xlink", namespaceURI = XLINK), + @XmlNs(prefix = "run", namespaceURI = RUN) }) +package org.taverna.server.port_description; + +import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED; +import static org.taverna.server.port_description.Namespaces.DATA; +import static org.taverna.server.port_description.Namespaces.RUN; +import static org.taverna.server.port_description.Namespaces.XLINK; + +import javax.xml.bind.annotation.XmlNs; +import javax.xml.bind.annotation.XmlSchema; + http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java new file mode 100644 index 0000000..8764176 --- /dev/null +++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.port_description.utils; + +import static javax.xml.bind.DatatypeConverter.parseInt; +import static javax.xml.bind.DatatypeConverter.printInt; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +/** + * A type conversion utility for use with JAXB. + * + * @author Donal Fellows + */ +public class IntAdapter extends XmlAdapter<String, Integer> { + @Override + public String marshal(Integer value) throws Exception { + if (value == null) + return null; + return printInt(value); + } + + @Override + public Integer unmarshal(String value) throws Exception { + if (value == null) + return null; + return parseInt(value); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java ---------------------------------------------------------------------- diff --git a/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java b/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java new file mode 100644 index 0000000..c952ec2 --- /dev/null +++ b/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java @@ -0,0 +1,98 @@ +package org.taverna.server.port_description; + +import java.io.IOException; +import java.io.StringWriter; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.SchemaOutputResolver; +import javax.xml.transform.Result; +import javax.xml.transform.stream.StreamResult; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * This test file ensures that the JAXB bindings will work once deployed instead + * of mysteriously failing in service. + * + * @author Donal Fellows + */ +public class JaxbSanityTest { + SchemaOutputResolver sink; + StringWriter schema; + + String schema() { + return schema.toString(); + } + + private String schemaTest(Class<?>... classes) throws IOException, JAXBException { + Assert.assertTrue(schema().isEmpty()); + JAXBContext.newInstance(classes).generateSchema(sink); + Assert.assertFalse(schema().isEmpty()); + return schema(); + } + + @Before + public void init() { + schema = new StringWriter(); + sink = new SchemaOutputResolver() { + @Override + public Result createOutput(String namespaceUri, + String suggestedFileName) throws IOException { + StreamResult sr = new StreamResult(schema); + sr.setSystemId("/dev/null"); + return sr; + } + }; + } + + @Test + public void testJAXBForInput() throws Exception { + schemaTest(InputDescription.InputPort.class); + } + + @Test + public void testJAXBForInputDescription() throws Exception { + schemaTest(InputDescription.class); + } + + @Test + public void testJAXBForAbsentValue() throws Exception { + schemaTest(AbstractValue.class); + } + + @Test + public void testJAXBForAbstractValue() throws Exception { + schemaTest(AbstractValue.class); + } + + @Test + public void testJAXBForErrorValue() throws Exception { + schemaTest(ErrorValue.class); + } + + @Test + public void testJAXBForLeafValue() throws Exception { + schemaTest(LeafValue.class); + } + + @Test + public void testJAXBForListValue() throws Exception { + schemaTest(ListValue.class); + } + + @Test + public void testJAXBForOutputDescription() throws Exception { + schemaTest(OutputDescription.class); + } + + @Test + public void testJAXBForEverythingAtOnce() throws Exception { + schemaTest(AbsentValue.class, AbstractValue.class, ListValue.class, + LeafValue.class, ErrorValue.class, OutputDescription.class, + InputDescription.InputPort.class, InputDescription.class); + // System.out.println(schema()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-rmidaemon/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-server-rmidaemon/pom.xml b/taverna-server-rmidaemon/pom.xml new file mode 100644 index 0000000..0e2a565 --- /dev/null +++ b/taverna-server-rmidaemon/pom.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.taverna.server</groupId> + <artifactId>taverna-server</artifactId> + <version>3.1.0-incubating-SNAPSHOT</version> + </parent> + + <artifactId>taverna-server-rmidaemon</artifactId> + <name>Apache Taverna Server RMI registry daemon</name> + <description>Customised RMI registry that supports restricting to localhost.</description> + + <properties> + <project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding> + <mainClass>org.taverna.server.rmidaemon.Registry</mainClass> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <configuration> + <descriptorRefs> + <descriptorRef>jar-with-dependencies</descriptorRef> + </descriptorRefs> + <archive> + <manifest> + <mainClass>${mainClass}</mainClass> + </manifest> + </archive> + </configuration> + <executions> + <execution> + <id>make-assembly</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java ---------------------------------------------------------------------- diff --git a/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java new file mode 100644 index 0000000..4be7579 --- /dev/null +++ b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java @@ -0,0 +1,72 @@ +package org.taverna.server.rmidaemon; + +import static java.lang.System.setProperty; +import static java.net.InetAddress.getLocalHost; +import static java.rmi.registry.LocateRegistry.createRegistry; +import static java.rmi.registry.Registry.REGISTRY_PORT; +import static java.rmi.server.RMISocketFactory.getDefaultSocketFactory; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.net.ServerSocket; +import java.rmi.MarshalledObject; +import java.rmi.server.RMIServerSocketFactory; + +/** + * Special version of <tt>rmiregistry</tt>. + * + * @author Donal Fellows + */ +public class Registry { + /** + * Run a registry. The first optional argument is the port for the registry + * to listen on, and the second optional argument is whether the registry + * should restrict itself to connections from localhost only. + * + * @param args + * Arguments to the program. + */ + public static void main(String... args) { + try { + if (args.length > 0) + port = Integer.parseInt(args[0]); + } catch (Exception e) { + System.err.println("failed to parse port: " + e.getMessage()); + System.exit(2); + } + try { + if (args.length > 1) + localhostOnly = Boolean.parseBoolean(args[1]); + } catch (Exception e) { + System.err.println("failed to parse boolean localhost flag: " + + e.getMessage()); + System.exit(2); + } + try { + Object registryHandle = makeRegistry(); + try (ObjectOutputStream oos = new ObjectOutputStream(System.out)) { + oos.writeObject(registryHandle); + } + } catch (Exception e) { + System.err.println("problem creating registry: " + e.getMessage()); + System.exit(1); + } + } + + private static int port = REGISTRY_PORT; + private static boolean localhostOnly = false; + + private static MarshalledObject<java.rmi.registry.Registry> makeRegistry() throws IOException { + if (!localhostOnly) + return new MarshalledObject<>(createRegistry(port)); + setProperty("java.rmi.server.hostname", "127.0.0.1"); + return new MarshalledObject<>(createRegistry(port, + getDefaultSocketFactory(), new RMIServerSocketFactory() { + @Override + public ServerSocket createServerSocket(int port) + throws IOException { + return new ServerSocket(port, 0, getLocalHost()); + } + })); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java ---------------------------------------------------------------------- diff --git a/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java new file mode 100644 index 0000000..32144b5 --- /dev/null +++ b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java @@ -0,0 +1,5 @@ +/** + * RMI daemon implementation. A variation of an RMI registry. + * @author Donal Fellows + */ +package org.taverna.server.rmidaemon; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/.gitignore ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/.gitignore b/taverna-server-runinterface/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/taverna-server-runinterface/.gitignore @@ -0,0 +1 @@ +/target http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/pom.xml b/taverna-server-runinterface/pom.xml new file mode 100644 index 0000000..efd3763 --- /dev/null +++ b/taverna-server-runinterface/pom.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.taverna.server</groupId> + <artifactId>taverna-server</artifactId> + <version>3.1.0-incubating-SNAPSHOT</version> + </parent> + + <artifactId>taverna-server-runinterface</artifactId> + <name>Apache Taverna Server RMI Interface: Webapp <-> Worker</name> + <description>This is the implementation of the RMI interface between the workflow run factory and the web-app service front-end.</description> + +</project> http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF b/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000..5e94951 --- /dev/null +++ b/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java new file mode 100644 index 0000000..9f4bf50 --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import javax.xml.ws.WebFault; + +/** + * Exception that indicates where a change of a workflow run's status is + * illegal. + * + * @author Donal Fellows + * @see RemoteSingleRun#setStatus(RemoteStatus) + */ +@WebFault(name = "IllegalStateTransitionFault", targetNamespace = "http://ns.taverna.org.uk/2010/xml/server/worker/") +public class IllegalStateTransitionException extends Exception { + private static final long serialVersionUID = 159673249162345L; + + public IllegalStateTransitionException() { + this("illegal state transition"); + } + + public IllegalStateTransitionException(String message) { + super(message); + } + + public IllegalStateTransitionException(Throwable cause) { + this("illegal state transition", cause); + } + + public IllegalStateTransitionException(String message, Throwable cause) { + super(message, cause); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java new file mode 100644 index 0000000..a47d112 --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import javax.xml.ws.WebFault; + +/** + * Exception that indicates that the implementation has gone wrong in some + * unexpected way. + * + * @author Donal Fellows + */ +@WebFault(name = "ImplementationFault", targetNamespace = "http://ns.taverna.org.uk/2010/xml/server/worker/") +@SuppressWarnings("serial") +public class ImplementationException extends Exception { + public ImplementationException(String message) { + super(message); + } + + public ImplementationException(String message, Throwable cause) { + super(message, cause); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java new file mode 100644 index 0000000..395842a --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.Collection; + +import javax.annotation.Nonnull; + +/** + * Represents a directory that is the working directory of a workflow run, or a + * sub-directory of it. + * + * @author Donal Fellows + * @see RemoteFile + */ +public interface RemoteDirectory extends RemoteDirectoryEntry { + /** + * @return A list of the contents of the directory. + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws IOException + * If anything goes wrong with listing the directory. + */ + @Nonnull + public Collection<RemoteDirectoryEntry> getContents() + throws RemoteException, IOException; + + /** + * Creates a sub-directory of this directory. + * + * @param name + * The name of the sub-directory. + * @return A handle to the newly-created directory. + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws IOException + * If things go wrong with creating the subdirectory. + */ + @Nonnull + public RemoteDirectory makeSubdirectory(@Nonnull String name) + throws RemoteException, IOException; + + /** + * Creates an empty file in this directory. + * + * @param name + * The name of the file to create. + * @return A handle to the newly-created file. + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws IOException + * If anything goes wrong with creating the file. + */ + @Nonnull + public RemoteFile makeEmptyFile(@Nonnull String name) + throws RemoteException, IOException; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java new file mode 100644 index 0000000..1e04b44 --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import java.io.IOException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.Date; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * An entry in a {@link RemoteDirectory} representing a file or sub-directory. + * + * @author Donal Fellows + * @see RemoteDirectory + * @see RemoteFile + */ +public interface RemoteDirectoryEntry extends Remote { + /** + * @return The "local" name of the entry. This will never be "<tt>..</tt>" + * or contain the character "<tt>/</tt>". + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public String getName() throws RemoteException; + + /** + * @return The time when the entry was last modified. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public Date getModificationDate() throws RemoteException; + + /** + * Gets the directory containing this directory entry. + * + * @return A directory handle, or <tt>null</tt> if called on the workflow + * run's working directory. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nullable + public RemoteDirectory getContainingDirectory() throws RemoteException; + + /** + * Destroy this directory entry, deleting the file or sub-directory. The + * workflow run's working directory can never be manually destroyed. + * + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws IOException + * If things go wrong when deleting the directory entry. + */ + public void destroy() throws RemoteException, IOException; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java new file mode 100644 index 0000000..e09466d --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import java.io.IOException; +import java.rmi.RemoteException; + +import javax.annotation.Nonnull; + +/** + * Represents a file in the working directory of a workflow instance run, or in + * some sub-directory of it. + * + * @author Donal Fellows + * @see RemoteDirectory + */ +public interface RemoteFile extends RemoteDirectoryEntry { + /** + * Read from the file. + * + * @param offset + * Where in the file to read the bytes from. + * @param length + * How much of the file to read; -1 for "to the end". + * @return The literal byte contents of the given section of the file. + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws IOException + * If things go wrong reading the file. + */ + @Nonnull + byte[] getContents(int offset, int length) throws RemoteException, + IOException; + + /** + * Write the data to the file, totally replacing what was there before. + * + * @param data + * The literal bytes that will form the new contents of the file. + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws IOException + * If things go wrong writing the contents. + */ + void setContents(@Nonnull byte[] data) throws RemoteException, IOException; + + /** + * Append the data to the file. + * + * @param data + * The literal bytes that will be appended. + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws IOException + * If things go wrong writing the contents. + */ + void appendContents(@Nonnull byte[] data) throws RemoteException, + IOException; + + /** + * @return The length of the file, in bytes. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + long getSize() throws RemoteException; + + /** + * Copy from another file to this one. + * + * @param sourceFile + * The other file to copy from. + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws IOException + * If things go wrong during the copy. + */ + void copy(@Nonnull RemoteFile sourceFile) throws RemoteException, + IOException; + + /** + * @return The full native OS name for the file. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + String getNativeName() throws RemoteException; + + /** + * @return The host holding the file. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + String getNativeHost() throws RemoteException; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java new file mode 100644 index 0000000..7a7510c --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * This represents the assignment of inputs to input ports of the workflow. Note + * that the <tt>file</tt> and <tt>value</tt> properties are never set at the + * same time. + * + * @author Donal Fellows + */ +public interface RemoteInput extends Remote { + /** + * @return The file currently assigned to this input port, or <tt>null</tt> + * if no file is assigned. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nullable + String getFile() throws RemoteException; + + /** + * @return The name of this input port. This may not be changed. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + String getName() throws RemoteException; + + /** + * @return The value currently assigned to this input port, or <tt>null</tt> + * if no value is assigned. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nullable + String getValue() throws RemoteException; + + /** + * @return The delimiter currently used to split this input port's value + * into a list, or <tt>null</tt> if no delimiter is to be used + * (i.e., the value is a singleton). + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nullable + String getDelimiter() throws RemoteException; + + /** + * Sets the file to use for this input. This overrides the use of the + * previous file and any set value. + * + * @param file + * The filename to use. Must not start with a <tt>/</tt> or + * contain any <tt>..</tt> segments. Will be interpreted relative + * to the run's working directory. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + void setFile(@Nonnull String file) throws RemoteException; + + /** + * Sets the value to use for this input. This overrides the use of the + * previous value and any set file. + * + * @param value + * The value to use. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + void setValue(@Nonnull String value) throws RemoteException; + + /** + * Sets the delimiter used to split this input port's value into a list. + * + * @param delimiter + * The delimiter character, or <tt>null</tt> if no delimiter is + * to be used (i.e., the value is a singleton). + * @throws RemoteException + * If anything goes wrong with the communication. + */ + void setDelimiter(@Nullable String delimiter) throws RemoteException; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java new file mode 100644 index 0000000..4001721 --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +import javax.annotation.Nonnull; + +/** + * An event listener that is attached to a {@link RemoteSingleRun}. + * + * @author Donal Fellows + */ +public interface RemoteListener extends Remote { + /** + * @return The name of the listener. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public String getName() throws RemoteException; + + /** + * @return The type of the listener. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public String getType() throws RemoteException; + + /** + * @return The configuration document for the listener. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public String getConfiguration() throws RemoteException; + + /** + * @return The supported properties of the listener. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public String[] listProperties() throws RemoteException; + + /** + * Get the value of a particular property, which should be listed in the + * {@link #listProperties()} method. + * + * @param propName + * The name of the property to read. + * @return The value of the property. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public String getProperty(@Nonnull String propName) throws RemoteException; + + /** + * Set the value of a particular property, which should be listed in the + * {@link #listProperties()} method. + * + * @param propName + * The name of the property to write. + * @param value + * The value to set the property to. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + public void setProperty(@Nonnull String propName, @Nonnull String value) + throws RemoteException; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java new file mode 100644 index 0000000..eec4ab5 --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.UUID; + +import org.taverna.server.localworker.server.UsageRecordReceiver; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * The main RMI-enabled interface for creating runs. + * + * @author Donal Fellows + */ +public interface RemoteRunFactory extends Remote { + /** + * Makes a workflow run that will process a particular workflow document. + * + * @param workflow + * The (serialised) workflow to instantiate as a run. + * @param creator + * Who is this run created for? + * @param usageRecordReceiver + * Where to write any usage records. May be <tt>null</tt> to + * cause them to not be written. + * @param masterID + * The UUID of the run to use, or <tt>null</tt> if the execution + * engine is to manufacture a new one for itself. + * @return A remote handle for the run. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + RemoteSingleRun make(@Nonnull byte[] workflow, @Nonnull String creator, + @Nullable UsageRecordReceiver usageRecordReceiver, + @Nullable UUID masterID) throws RemoteException; + + /** + * Asks this factory to unregister itself from the registry and cease + * operation. + * + * @throws RemoteException + * If anything goes wrong with the communication. + */ + void shutdown() throws RemoteException; + + /** + * Configures the details to use when setting up the workflow run's + * connnection to the interaction feed. + * + * @param host + * The host where the feed is located. + * @param port + * The port where the feed is located. + * @param webdavPath + * The path used for pushing web pages into the feed. + * @param feedPath + * The path used for reading and writing notifications on the + * feed. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + void setInteractionServiceDetails(@Nonnull String host, + @Nonnull String port, @Nonnull String webdavPath, + @Nonnull String feedPath) throws RemoteException; + + /** + * Gets a count of the number of {@linkplain RemoteSingleRun workflow runs} + * that this factor knows about that are in the + * {@link RemoteStatus#Operating Operating} state. + * + * @return A count of "running" workflow runs. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + int countOperatingRuns() throws RemoteException; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java new file mode 100644 index 0000000..35e6c09 --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010-2012 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import java.net.URI; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.Map; + +import javax.annotation.Nonnull; + +/** + * Outline of the security context for a workflow run. + * + * @author Donal Fellows + */ +public interface RemoteSecurityContext extends Remote { + void setKeystore(@Nonnull byte[] keystore) throws RemoteException, + ImplementationException; + + void setPassword(@Nonnull char[] password) throws RemoteException, + ImplementationException; + + void setTruststore(@Nonnull byte[] truststore) throws RemoteException, + ImplementationException; + + void setUriToAliasMap(@Nonnull Map<URI, String> uriToAliasMap) + throws RemoteException; + + void setHelioToken(@Nonnull String helioToken) throws RemoteException; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java new file mode 100644 index 0000000..fa68b81 --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +import java.net.URL; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.Date; +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public interface RemoteSingleRun extends Remote { + /** + * @return The name of the Baclava file to use for all inputs, or + * <tt>null</tt> if no Baclava file is set. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nullable + public String getInputBaclavaFile() throws RemoteException; + + /** + * Sets the Baclava file to use for all inputs. This overrides the use of + * individual inputs. + * + * @param filename + * The filename to use. Must not start with a <tt>/</tt> or + * contain any <tt>..</tt> segments. Will be interpreted relative + * to the run's working directory. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + public void setInputBaclavaFile(@Nonnull String filename) + throws RemoteException; + + /** + * @return The list of input assignments. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public List<RemoteInput> getInputs() throws RemoteException; + + /** + * Create an input assignment. + * + * @param name + * The name of the port that this will be an input for. + * @return The assignment reference. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public RemoteInput makeInput(@Nonnull String name) throws RemoteException; + + /** + * @return The file (relative to the working directory) to write the outputs + * of the run to as a Baclava document, or <tt>null</tt> if they are + * to be written to non-Baclava files in a directory called + * <tt>out</tt>. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nullable + public String getOutputBaclavaFile() throws RemoteException; + + /** + * Sets where the output of the run is to be written to. This will cause the + * output to be generated as a Baclava document, rather than a collection of + * individual non-Baclava files in the subdirectory of the working directory + * called <tt>out</tt>. + * + * @param filename + * Where to write the Baclava file (or <tt>null</tt> to cause the + * output to be written to individual files); overwrites any + * previous setting of this value. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + public void setOutputBaclavaFile(@Nullable String filename) + throws RemoteException; + + /** + * @return The current status of the run. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public RemoteStatus getStatus() throws RemoteException; + + /** + * Set the status of the run, which should cause it to move into the given + * state. This may cause some significant changes. + * + * @param s + * The state to try to change to. + * @throws IllegalStateTransitionException + * If the requested state change is impossible. (Note that it is + * always legal to set the status to the current status.) + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws ImplementationException + * If something goes horribly wrong on the back end. + * @throws StillWorkingOnItException + * If the startup time of the workflow implementation exceeds a + * built-in threshold. + */ + public void setStatus(@Nonnull RemoteStatus s) + throws IllegalStateTransitionException, RemoteException, + ImplementationException, StillWorkingOnItException; + + /** + * @return When this workflow run was found to have finished, or + * <tt>null</tt> if it has never finished (either still running or + * never started). + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nullable + public Date getFinishTimestamp() throws RemoteException; + + /** + * @return When this workflow run was started, or <tt>null</tt> if it has + * never been started. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nullable + public Date getStartTimestamp() throws RemoteException; + + /** + * @return Handle to the main working directory of the run. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public RemoteDirectory getWorkingDirectory() throws RemoteException; + + /** + * @return The list of listener instances attached to the run. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public List<RemoteListener> getListeners() throws RemoteException; + + /** + * Add a listener to the run. + * + * @param listener + * The listener to add. + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws ImplementationException + * If something goes wrong when adding the listener. + */ + public void addListener(@Nonnull RemoteListener listener) + throws RemoteException, ImplementationException; + + /** + * @return The security context structure for this run. + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws ImplementationException + * If something goes wrong when getting the context. + */ + @Nonnull + public RemoteSecurityContext getSecurityContext() throws RemoteException, + ImplementationException; + + /** + * Kill off this run, removing all resources which it consumes. + * + * @throws RemoteException + * If anything goes wrong with the communication. + * @throws ImplementationException + * If something goes horribly wrong when destroying the run. + */ + public void destroy() throws RemoteException, ImplementationException; + + /** + * Get the types of listener supported by this run. + * + * @return A list of listener type names. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public List<String> getListenerTypes() throws RemoteException; + + /** + * Create a listener that can be attached to this run. + * + * @param type + * The type name of the listener to create; it must be one of the + * names returned by the {@link #getListenerTypes()} operation. + * @param configuration + * The configuration document for this listener. The nature of + * the contents of this are determined by the type. + * @return A handle for the listener. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + @Nonnull + public RemoteListener makeListener(@Nonnull String type, + @Nonnull String configuration) throws RemoteException; + + /** + * Configures the details to use when setting up the workflow run's + * connnection to the interaction feed. + * + * @param interactionFeed + * The location of the interaction feed. If <tt>null</tt>, + * defaults from the factory will be used instead. + * @param webdavPath + * The location used for pushing web pages to support the feed. + * If <tt>null</tt>, a default from the factory will be used + * instead. + * @param publishUrlBase + * Where to <i>actually</i> publish to, if this needs to be + * different from the location presented in the published HTML + * and Feed entries. Necessary in complex network scenarios. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + void setInteractionServiceDetails(@Nonnull URL interactionFeed, + @Nonnull URL webdavPath, @Nullable URL publishUrlBase) throws RemoteException; + + /** + * A do-nothing method, used to check the general reachability of the + * workflow run. + * + * @throws RemoteException + * If anything goes wrong with the communication. + */ + void ping() throws RemoteException; + + /** + * Sets whether we should generate provenance information from a run. + * + * @param generateProvenance + * Boolean flag, true for do the generation. Must be set before + * starting the run for this to have an effect. + * @throws RemoteException + * If anything goes wrong with the communication. + */ + void setGenerateProvenance(boolean generateProvenance) + throws RemoteException; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java new file mode 100644 index 0000000..db039f0 --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +/** + * States of a workflow run. They are {@link RemoteStatus#Initialized + * Initialized}, {@link RemoteStatus#Operating Operating}, + * {@link RemoteStatus#Stopped Stopped}, and {@link RemoteStatus#Finished + * Finished}. Conceptually, there is also a <tt>Destroyed</tt> state, but the + * workflow run does not exist (and hence can't have its state queried or set) + * in that case. + * + * @author Donal Fellows + */ +public enum RemoteStatus { + /** + * The workflow run has been created, but is not yet running. The run will + * need to be manually moved to {@link #Operating} when ready. + */ + Initialized, + /** + * The workflow run is going, reading input, generating output, etc. Will + * eventually either move automatically to {@link #Finished} or can be moved + * manually to {@link #Stopped} (where supported). + */ + Operating, + /** + * The workflow run is paused, and will need to be moved back to + * {@link #Operating} manually. + */ + Stopped, + /** + * The workflow run has ceased; data files will continue to exist until the + * run is destroyed (which may be manual or automatic). + */ + Finished +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java new file mode 100644 index 0000000..4643d5c --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.remote; + +/** + * Exception that indicates that the implementation is still working on + * processing the operation. Note that though this is an exception, it is <i>not + * a failure</i>. + * + * @author Donal Fellows + */ +@SuppressWarnings("serial") +public class StillWorkingOnItException extends Exception { + public StillWorkingOnItException(String string) { + super(string); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java new file mode 100644 index 0000000..9880a3b --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +/** + * Interfaces exported by worker classes to the server. + */ +package org.taverna.server.localworker.remote; http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java new file mode 100644 index 0000000..89c29ae --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.localworker.server; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +/** + * Interface exported by (part of) the webapp to allow processes it creates to + * push in usage records. + * + * @author Donal Fellows + */ +public interface UsageRecordReceiver extends Remote { + /** + * Called to push in a usage record. Note that it is assumed that the usage + * record already contains all the information required to locate and + * process the job; there is no separate handle. + * + * @param usageRecord + * The serialised XML of the usage record. + * @throws RemoteException + * if anything goes wrong. + */ + void acceptUsageRecord(String usageRecord) throws RemoteException; +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java ---------------------------------------------------------------------- diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java new file mode 100644 index 0000000..cdd592b --- /dev/null +++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +/** + * Interfaces exported by the server to worker classes. + */ +package org.taverna.server.localworker.server; http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-unix-forker/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-server-unix-forker/pom.xml b/taverna-server-unix-forker/pom.xml new file mode 100644 index 0000000..a2beeb4 --- /dev/null +++ b/taverna-server-unix-forker/pom.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.taverna.server</groupId> + <artifactId>taverna-server</artifactId> + <version>3.1.0-incubating-SNAPSHOT</version> + </parent> + <artifactId>taverna-server-unix-forker</artifactId> + <name>Apache Taverna Server Impersonation Module (Unix)</name> + <description>Manages the starting of the worker processes as different users. Unix-specific.</description> + + <properties> + <project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding> + <forkerMainClass>org.taverna.server.unixforker.Forker</forkerMainClass> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <configuration> + <descriptorRefs> + <descriptorRef>jar-with-dependencies</descriptorRef> + </descriptorRefs> + <archive> + <manifest> + <mainClass>${forkerMainClass}</mainClass> + </manifest> + </archive> + </configuration> + <executions> + <execution> + <id>make-assembly</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java ---------------------------------------------------------------------- diff --git a/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java b/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java new file mode 100644 index 0000000..f9dc632 --- /dev/null +++ b/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2010-2011 The University of Manchester + * + * See the file "LICENSE" for license terms. + */ +package org.taverna.server.unixforker; + +import static java.lang.System.err; +import static java.lang.System.getProperty; +import static java.lang.System.in; +import static java.lang.System.out; +import static java.util.Arrays.asList; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.List; + +import javax.annotation.Nonnull; + +/** + * A simple class that forks off processes when asked to over its standard + * input. The one complication is that it forks them off as other users, through + * the use of the <tt>sudo</tt> utility. It is Unix-specific. + * + * @author Donal Fellows + */ +public class Forker extends Thread { + private static String password; + private static BufferedReader br; + + /** + * Helper to make reading a password from a file clearer. The password must + * be the first line of the file. + * + * @param passwordFile + * The file to load from. + * @throws IOException + * If anything goes wrong. + */ + private static void loadPassword(@Nonnull File passwordFile) + throws IOException { + try { + err.println("attempting to load password from " + passwordFile); + try (FileReader fr = new FileReader(passwordFile)) { + password = new BufferedReader(fr).readLine(); + } + } catch (IOException e) { + err.println("failed to read password from file " + passwordFile + + "described in password.file property"); + throw e; + } + } + + /** + * Initialization code, which runs before the main loop starts processing. + * + * @param args + * The arguments to the program. + * @throws Exception + * If anything goes wrong. + */ + public static void init(String[] args) throws Exception { + if (args.length < 1) + throw new IllegalArgumentException( + "wrong # args: must be \"program ?argument ...?\""); + if (getProperty("password.file") != null) + loadPassword(new File(getProperty("password.file"))); + if (password == null) + err.println("no password.file property or empty file; " + + "assuming password-less sudo is configured"); + else + err.println("password is of length " + password.length()); + br = new BufferedReader(new InputStreamReader(in)); + } + + /** + * The body of the main loop of this program. + * + * @param args + * The arguments to use when running the other program. + * @return Whether to repeat the loop. + * @throws Exception + * If anything goes wrong. Note that the loop is repeated if an + * exception occurs in it. + */ + public static boolean mainLoopBody(String[] args) throws Exception { + String line = br.readLine(); + if (line == null) + return false; + List<String> vals = asList(line.split("[ \t]+")); + if (vals.size() != 2) { + out.println("wrong # values: must be \"username UUID\""); + return true; + } + ProcessBuilder pb = new ProcessBuilder(); + pb.command() + .addAll(asList("sudo", "-u", vals.get(0), "-S", "-H", "--")); + pb.command().addAll(asList(args)); + pb.command().add(vals.get(1)); + Forker f = new Forker(pb); + f.setDaemon(true); + f.start(); + return true; + } + + /** + * The main code for this class, which turns this into an executable + * program. Runs the initialisation and then the main loop, in both cases + * with appropriate error handling. + * + * @param args + * Arguments to this program. + */ + public static void main(String... args) { + try { + init(args); + while (true) { + try { + if (!mainLoopBody(args)) + break; + } catch (Exception e) { + e.printStackTrace(err); + out.println(e.getClass().getName() + ": " + e.getMessage()); + } + } + System.exit(0); + } catch (Exception e) { + e.printStackTrace(err); + System.exit(1); + } + } + + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + public Forker(ProcessBuilder pb) throws IOException { + out.println("Starting subprocess: " + pb.command()); + final Process p = pb.start(); + abstract class ProcessAttachedDaemon extends Thread { + public ProcessAttachedDaemon() { + setDaemon(true); + start(); + } + + abstract void act() throws Exception; + + @Override + public final void run() { + try { + act(); + p.waitFor(); + } catch (InterruptedException e) { + // Just drop + } catch (Exception e) { + p.destroy(); + e.printStackTrace(err); + } + } + } + new ProcessAttachedDaemon() { + @Override + void act() throws Exception { + copyFromSudo("Subprocess(out):", p.getInputStream()); + } + }; + new ProcessAttachedDaemon() { + @Override + void act() throws Exception { + copyFromSudo("Subprocess(err):", p.getErrorStream()); + } + }; + new ProcessAttachedDaemon() { + @Override + void act() throws Exception { + interactWithSudo(p.getOutputStream()); + } + }; + } + + protected void interactWithSudo(OutputStream os) throws Exception { + if (password != null) { + OutputStreamWriter osw = new OutputStreamWriter(os); + osw.write(password + "\n"); + osw.flush(); + } + os.close(); + } + + protected void copyFromSudo(String header, InputStream sudoStream) + throws Exception { + int b = '\n'; + while (true) { + if (b == '\n') + out.print(header); + b = sudoStream.read(); + if (b == -1) + break; + out.write(b); + out.flush(); + } + sudoStream.close(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/.gitignore ---------------------------------------------------------------------- diff --git a/taverna-server-usagerecord/.gitignore b/taverna-server-usagerecord/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/taverna-server-usagerecord/.gitignore @@ -0,0 +1 @@ +/target http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-server-usagerecord/pom.xml b/taverna-server-usagerecord/pom.xml new file mode 100644 index 0000000..47ab732 --- /dev/null +++ b/taverna-server-usagerecord/pom.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.taverna.server</groupId> + <artifactId>taverna-server</artifactId> + <version>3.1.0-incubating-SNAPSHOT</version> + </parent> + <artifactId>taverna-server-usagerecord</artifactId> + <name>Apache Taverna Server Usage Record Support</name> + <description>Basic Java bindings for the OGF Usage Record Format, version 1.0, plus a simple wrapper to make working with it easier.</description> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>jaxb2-maven-plugin</artifactId> + <version>1.3.1</version> + <executions> + <execution> + <id>xsd2java</id> + <goals> + <goal>xjc</goal> + </goals> + <configuration> + <outputDirectory>${project.build.directory}/generated-sources/xjc</outputDirectory> + <schemaDirectory>${basedir}/src/main/xsd</schemaDirectory> + </configuration> + </execution> + </executions> + </plugin> + + </plugins> + <pluginManagement> + <plugins> + <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.--> + <plugin> + <groupId>org.eclipse.m2e</groupId> + <artifactId>lifecycle-mapping</artifactId> + <version>1.0.0</version> + <configuration> + <lifecycleMappingMetadata> + <pluginExecutions> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.codehaus.mojo</groupId> + <artifactId>jaxb2-maven-plugin</artifactId> + <versionRange>[1.3.1,)</versionRange> + <goals> + <goal>xjc</goal> + </goals> + </pluginExecutionFilter> + <action> + <execute /> + </action> + </pluginExecution> + </pluginExecutions> + </lifecycleMappingMetadata> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> +</project>
