http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
 
b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
new file mode 100644
index 0000000..69705d9
--- /dev/null
+++ 
b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/InteractionFeedREST.java
@@ -0,0 +1,139 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static org.taverna.server.master.rest.ContentTypes.ATOM;
+
+import java.net.MalformedURLException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+
+/**
+ * A very stripped down ATOM feed for the interaction service.
+ * 
+ * @author Donal Fellows
+ */
+public interface InteractionFeedREST {
+       /**
+        * Get the feed document for this ATOM feed.
+        * 
+        * @return The feed.
+        * @throws FilesystemAccessException
+        *             If we can't read from the feed directory.
+        * @throws NoDirectoryEntryException
+        *             If something changes things under our feet.
+        */
+       @GET
+       @Path("/")
+       @Produces(ATOM)
+       @Description("Get the feed document for this ATOM feed.")
+       Feed getFeed() throws FilesystemAccessException, 
NoDirectoryEntryException;
+
+       /**
+        * Adds an entry to this ATOM feed.
+        * 
+        * @param entry
+        *            The entry to create.
+        * @return A redirect to the created entry.
+        * @throws MalformedURLException
+        *             If we have problems generating the URI of the entry.
+        * @throws FilesystemAccessException
+        *             If we can't create the feed entry file.
+        * @throws NoDirectoryEntryException
+        *             If things get changed under our feet.
+        * @throws NoUpdateException
+        *             If we don't have permission to change things relating to 
this
+        *             run.
+        */
+       @POST
+       @Path("/")
+       @Consumes(ATOM)
+       @Produces(ATOM)
+       @Description("Adds an entry to this ATOM feed.")
+       Response addEntry(Entry entry) throws MalformedURLException,
+                       FilesystemAccessException, NoDirectoryEntryException,
+                       NoUpdateException;
+
+       /** Handles the OPTIONS request. */
+       @OPTIONS
+       @Path("/")
+       @Description("Describes what HTTP operations are supported on the 
feed.")
+       Response feedOptions();
+
+       /**
+        * Gets the content of an entry in this ATOM feed.
+        * 
+        * @param id
+        *            The ID of the entry to fetch.
+        * @return The entry contents.
+        * @throws FilesystemAccessException
+        *             If we have problems reading the entry.
+        * @throws NoDirectoryEntryException
+        *             If we can't find the entry to read.
+        */
+       @GET
+       @Path("{id}")
+       @Produces(ATOM)
+       @Description("Get the entry with a particular ID within this ATOM 
feed.")
+       Entry getEntry(@PathParam("id") String id)
+                       throws FilesystemAccessException, 
NoDirectoryEntryException;
+
+       /**
+        * Delete an entry from this ATOM feed.
+        * 
+        * @param id
+        *            The ID of the entry to delete.
+        * @return A simple message. Not very important!
+        * @throws FilesystemAccessException
+        *             If we have problems deleting the entry.
+        * @throws NoDirectoryEntryException
+        *             If we can't find the entry to delete.
+        * @throws NoUpdateException
+        *             If we don't have permission to alter things relating to 
this
+        *             run.
+        */
+       @DELETE
+       @Path("{id}")
+       @Produces("text/plain")
+       @Description("Deletes an entry from this ATOM feed.")
+       String deleteEntry(@PathParam("id") String id)
+                       throws FilesystemAccessException, 
NoDirectoryEntryException,
+                       NoUpdateException;
+
+       /** Handles the OPTIONS request. */
+       @OPTIONS
+       @Path("{id}")
+       @Description("Describes what HTTP operations are supported on an 
entry.")
+       Response entryOptions(@PathParam("{id}") String id);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
 
b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
new file mode 100644
index 0000000..f877d7a
--- /dev/null
+++ 
b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/ListenerDefinition.java
@@ -0,0 +1,45 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+/**
+ * Description of what sort of event listener to create and attach to a 
workflow
+ * run. Bound via JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement(name = "listenerDefinition")
+@XmlType(name="ListenerDefinition")
+public class ListenerDefinition {
+       /**
+        * The type of event listener to create.
+        */
+       @XmlAttribute
+       public String type;
+       /**
+        * How the event listener should be configured.
+        */
+       @XmlValue
+       public String configuration;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
 
b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
new file mode 100644
index 0000000..52e6d04
--- /dev/null
+++ 
b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/MakeOrUpdateDirEntry.java
@@ -0,0 +1,69 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+/**
+ * The input to the REST interface for making directories and files, and
+ * uploading file contents. Done with JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement(name = "filesystemOperation")
+@XmlType(name = "FilesystemCreationOperation")
+@XmlSeeAlso( { MakeOrUpdateDirEntry.MakeDirectory.class,
+               MakeOrUpdateDirEntry.SetFileContents.class })
+public abstract class MakeOrUpdateDirEntry {
+       /**
+        * The name of the file or directory that the operation applies to.
+        */
+       @XmlAttribute
+       public String name;
+       /**
+        * The contents of the file to upload.
+        */
+       @XmlValue
+       public byte[] contents;
+
+       /**
+        * Create a directory, described with JAXB. Should leave the
+        * {@link MakeOrUpdateDirEntry#contents contents} field empty.
+        * 
+        * @author Donal Fellows
+        */
+       @XmlRootElement(name = "mkdir")
+       @XmlType(name = "MakeDirectory")
+       public static class MakeDirectory extends MakeOrUpdateDirEntry {
+       }
+
+       /**
+        * Create a file or set its contents, described with JAXB.
+        * 
+        * @author Donal Fellows
+        */
+       @XmlRootElement(name = "upload")
+       @XmlType(name = "UploadFile")
+       public static class SetFileContents extends MakeOrUpdateDirEntry {
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/00397eff/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
----------------------------------------------------------------------
diff --git 
a/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
 
b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
new file mode 100644
index 0000000..1ed8a64
--- /dev/null
+++ 
b/taverna-server-webapp/src/main/java/org/apache/taverna/server/master/rest/TavernaServerDirectoryREST.java
@@ -0,0 +1,253 @@
+/*
+ */
+package org.taverna.server.master.rest;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static java.util.Collections.unmodifiableList;
+import static javax.ws.rs.core.MediaType.WILDCARD;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.rest.ContentTypes.BYTES;
+import static org.taverna.server.master.rest.ContentTypes.JSON;
+import static org.taverna.server.master.rest.ContentTypes.URI_LIST;
+import static org.taverna.server.master.rest.ContentTypes.XML;
+import static org.taverna.server.master.rest.ContentTypes.ZIP;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.PathSegment;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.Variant;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * Representation of how a workflow run's working directory tree looks.
+ * 
+ * @author Donal Fellows
+ */
+@RolesAllowed(USER)
+@Produces({ XML, JSON })
+@Consumes({ XML, JSON })
+@Description("Representation of how a workflow run's working directory tree 
looks.")
+public interface TavernaServerDirectoryREST {
+       /**
+        * Get the working directory of the workflow run.
+        * 
+        * @param ui
+        *            About how this method was called.
+        * @return A description of the working directory.
+        * @throws FilesystemAccessException
+        */
+       @GET
+       @Path("/")
+       @Description("Describes the working directory of the workflow run.")
+       @Nonnull
+       DirectoryContents getDescription(@Nonnull @Context UriInfo ui)
+                       throws FilesystemAccessException;
+
+       /** Get an outline of the operations supported. */
+       @OPTIONS
+       @Path("{path:.*}")
+       @Description("Produces the description of the files/directories' 
baclava operations.")
+       Response options(@PathParam("path") List<PathSegment> path);
+
+       /**
+        * Gets a description of the named entity in or beneath the working
+        * directory of the workflow run, which may be either a {@link 
Directory} or
+        * a {@link File}.
+        * 
+        * @param path
+        *            The path to the thing to describe.
+        * @param ui
+        *            About how this method was called.
+        * @param headers
+        *            About what the caller was looking for.
+        * @return An HTTP response containing a description of the named thing.
+        * @throws NoDirectoryEntryException
+        *             If the name of the file or directory can't be looked up.
+        * @throws FilesystemAccessException
+        *             If something went wrong during the filesystem operation.
+        * @throws NegotiationFailedException
+        *             If the content type being downloaded isn't one that this
+        *             method can support.
+        */
+       @GET
+       @Path("{path:.+}")
+       @Produces({ XML, JSON, BYTES, ZIP, WILDCARD })
+       @Description("Gives a description of the named entity in or beneath the 
"
+                       + "working directory of the workflow run (either a 
Directory or File).")
+       @Nonnull
+       Response getDirectoryOrFileContents(
+                       @Nonnull @PathParam("path") List<PathSegment> path,
+                       @Nonnull @Context UriInfo ui, @Nonnull @Context 
HttpHeaders headers)
+                       throws NoDirectoryEntryException, 
FilesystemAccessException,
+                       NegotiationFailedException;
+
+       /**
+        * Creates a directory in the filesystem beneath the working directory 
of
+        * the workflow run, or creates or updates a file's contents, where that
+        * file is in or below the working directory of a workflow run.
+        * 
+        * @param parent
+        *            The directory to create the directory in.
+        * @param operation
+        *            What to call the directory to create.
+        * @param ui
+        *            About how this method was called.
+        * @return An HTTP response indicating where the directory was actually 
made
+        *         or what file was created/updated.
+        * @throws NoDirectoryEntryException
+        *             If the name of the containing directory can't be looked 
up.
+        * @throws NoUpdateException
+        *             If the user is not permitted to update the run.
+        * @throws FilesystemAccessException
+        *             If something went wrong during the filesystem operation.
+        */
+       @POST
+       @Path("{path:.*}")
+       @Description("Creates a directory in the filesystem beneath the working 
"
+                       + "directory of the workflow run, or creates or updates 
a file's "
+                       + "contents, where that file is in or below the working 
directory "
+                       + "of a workflow run.")
+       @Nonnull
+       Response makeDirectoryOrUpdateFile(
+                       @Nonnull @PathParam("path") List<PathSegment> parent,
+                       @Nonnull MakeOrUpdateDirEntry operation,
+                       @Nonnull @Context UriInfo ui) throws NoUpdateException,
+                       FilesystemAccessException, NoDirectoryEntryException;
+
+       /**
+        * Creates or updates a file in a particular location beneath the 
working
+        * directory of the workflow run.
+        * 
+        * @param file
+        *            The path to the file to create or update.
+        * @param referenceList
+        *            Location to get the file's contents from. Must be
+        *            <i>publicly</i> readable.
+        * @param ui
+        *            About how this method was called.
+        * @return An HTTP response indicating what file was created/updated.
+        * @throws NoDirectoryEntryException
+        *             If the name of the containing directory can't be looked 
up.
+        * @throws NoUpdateException
+        *             If the user is not permitted to update the run.
+        * @throws FilesystemAccessException
+        *             If something went wrong during the filesystem operation.
+        */
+       @POST
+       @Path("{path:(.*)}")
+       @Consumes(URI_LIST)
+       @Description("Creates or updates a file in a particular location 
beneath the "
+                       + "working directory of the workflow run with the 
contents of a "
+                       + "publicly readable URL.")
+       @Nonnull
+       Response setFileContentsFromURL(@PathParam("path") List<PathSegment> 
file,
+                       List<URI> referenceList, @Context UriInfo ui)
+                       throws NoDirectoryEntryException, NoUpdateException,
+                       FilesystemAccessException;
+
+    /**
+        * Creates or updates a file in a particular location beneath the 
working
+        * directory of the workflow run.
+        * 
+        * @param file
+        *            The path to the file to create or update.
+        * @param contents
+        *            Stream of bytes to set the file's contents to.
+        * @param ui
+        *            About how this method was called.
+        * @return An HTTP response indicating what file was created/updated.
+        * @throws NoDirectoryEntryException
+        *             If the name of the containing directory can't be looked 
up.
+        * @throws NoUpdateException
+        *             If the user is not permitted to update the run.
+        * @throws FilesystemAccessException
+        *             If something went wrong during the filesystem operation.
+        */
+       @PUT
+       @Path("{path:(.*)}")
+       @Consumes({ BYTES, WILDCARD })
+       @Description("Creates or updates a file in a particular location 
beneath the "
+                       + "working directory of the workflow run.")
+       @Nonnull
+       Response setFileContents(@PathParam("path") List<PathSegment> file,
+                       InputStream contents, @Context UriInfo ui)
+                       throws NoDirectoryEntryException, NoUpdateException,
+                       FilesystemAccessException;
+
+       /**
+        * Deletes a file or directory that is in or below the working 
directory of
+        * a workflow run.
+        * 
+        * @param path
+        *            The path to the file or directory.
+        * @return An HTTP response to the method.
+        * @throws NoUpdateException
+        *             If the user is not permitted to update the run.
+        * @throws FilesystemAccessException
+        *             If something went wrong during the filesystem operation.
+        * @throws NoDirectoryEntryException
+        *             If the name of the file or directory can't be looked up.
+        */
+       @DELETE
+       @Path("{path:.*}")
+       @Description("Deletes a file or directory that is in or below the 
working "
+                       + "directory of a workflow run.")
+       @Nonnull
+       Response destroyDirectoryEntry(@PathParam("path") List<PathSegment> 
path)
+                       throws NoUpdateException, FilesystemAccessException,
+                       NoDirectoryEntryException;
+
+       /**
+        * Exception thrown to indicate a failure by the client to provide an
+        * acceptable content type.
+        * 
+        * @author Donal Fellows
+        */
+       @SuppressWarnings("serial")
+       public static class NegotiationFailedException extends Exception {
+               public List<Variant> accepted;
+
+               public NegotiationFailedException(String msg, List<Variant> 
accepted) {
+                       super(msg);
+                       this.accepted = unmodifiableList(accepted);
+               }
+       }
+}

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

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

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

Reply via email to