blob: 62158bb6fc6e3923b7972a7db1d4488500931441 [file] [log] [blame]
/*
* Copyright (C) 2010-2011 The University of Manchester
*
* See the file "LICENSE" for license terms.
*/
package org.taverna.server.master.rest;
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;
}
}