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