http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java ---------------------------------------------------------------------- diff --git a/server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java b/server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java deleted file mode 100644 index 0f98da6..0000000 --- a/server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java +++ /dev/null @@ -1,1425 +0,0 @@ -/* - * Copyright (C) 2010-2011 The University of Manchester - * - * See the file "LICENSE" for license terms. - */ -package org.taverna.server.master; - -import static java.lang.Math.min; -import static java.util.Collections.emptyMap; -import static java.util.Collections.sort; -import static java.util.UUID.randomUUID; -import static javax.ws.rs.core.Response.created; -import static javax.ws.rs.core.UriBuilder.fromUri; -import static javax.xml.ws.handler.MessageContext.HTTP_REQUEST_HEADERS; -import static javax.xml.ws.handler.MessageContext.PATH_INFO; -import static org.apache.commons.io.IOUtils.toByteArray; -import static org.apache.commons.logging.LogFactory.getLog; -import static org.taverna.server.master.TavernaServerSupport.PROV_BUNDLE; -import static org.taverna.server.master.common.DirEntryReference.newInstance; -import static org.taverna.server.master.common.Namespaces.SERVER_SOAP; -import static org.taverna.server.master.common.Roles.ADMIN; -import static org.taverna.server.master.common.Roles.SELF; -import static org.taverna.server.master.common.Roles.USER; -import static org.taverna.server.master.common.Status.Initialized; -import static org.taverna.server.master.common.Uri.secure; -import static org.taverna.server.master.soap.DirEntry.convert; -import static org.taverna.server.master.utils.RestUtils.opt; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.lang.ref.Reference; -import java.lang.ref.WeakReference; -import java.net.URI; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.PreDestroy; -import javax.annotation.Resource; -import javax.annotation.security.DeclareRoles; -import javax.annotation.security.RolesAllowed; -import javax.jws.WebService; -import javax.ws.rs.Path; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; -import javax.ws.rs.core.UriInfo; -import javax.xml.bind.JAXBException; -import javax.xml.ws.WebServiceContext; - -import org.apache.commons.logging.Log; -import org.apache.cxf.annotations.WSDLDocumentation; -import org.ogf.usage.JobUsageRecord; -import org.springframework.beans.factory.annotation.Required; -import org.taverna.server.master.api.SupportAware; -import org.taverna.server.master.api.TavernaServerBean; -import org.taverna.server.master.common.Capability; -import org.taverna.server.master.common.Credential; -import org.taverna.server.master.common.DirEntryReference; -import org.taverna.server.master.common.InputDescription; -import org.taverna.server.master.common.Permission; -import org.taverna.server.master.common.ProfileList; -import org.taverna.server.master.common.RunReference; -import org.taverna.server.master.common.Status; -import org.taverna.server.master.common.Trust; -import org.taverna.server.master.common.Workflow; -import org.taverna.server.master.common.version.Version; -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.InvalidCredentialException; -import org.taverna.server.master.exceptions.NoCreateException; -import org.taverna.server.master.exceptions.NoCredentialException; -import org.taverna.server.master.exceptions.NoDirectoryEntryException; -import org.taverna.server.master.exceptions.NoListenerException; -import org.taverna.server.master.exceptions.NoUpdateException; -import org.taverna.server.master.exceptions.NotOwnerException; -import org.taverna.server.master.exceptions.OverloadedException; -import org.taverna.server.master.exceptions.UnknownRunException; -import org.taverna.server.master.factories.ListenerFactory; -import org.taverna.server.master.interfaces.Directory; -import org.taverna.server.master.interfaces.DirectoryEntry; -import org.taverna.server.master.interfaces.File; -import org.taverna.server.master.interfaces.Input; -import org.taverna.server.master.interfaces.Listener; -import org.taverna.server.master.interfaces.Policy; -import org.taverna.server.master.interfaces.RunStore; -import org.taverna.server.master.interfaces.TavernaRun; -import org.taverna.server.master.interfaces.TavernaSecurityContext; -import org.taverna.server.master.notification.NotificationEngine; -import org.taverna.server.master.notification.atom.EventDAO; -import org.taverna.server.master.rest.TavernaServerREST; -import org.taverna.server.master.rest.TavernaServerREST.EnabledNotificationFabrics; -import org.taverna.server.master.rest.TavernaServerREST.PermittedListeners; -import org.taverna.server.master.rest.TavernaServerREST.PermittedWorkflows; -import org.taverna.server.master.rest.TavernaServerREST.PolicyView; -import org.taverna.server.master.rest.TavernaServerRunREST; -import org.taverna.server.master.soap.DirEntry; -import org.taverna.server.master.soap.FileContents; -import org.taverna.server.master.soap.PermissionList; -import org.taverna.server.master.soap.TavernaServerSOAP; -import org.taverna.server.master.soap.WrappedWorkflow; -import org.taverna.server.master.soap.ZippedDirectory; -import org.taverna.server.master.utils.CallTimeLogger.PerfLogged; -import org.taverna.server.master.utils.FilenameUtils; -import org.taverna.server.master.utils.InvocationCounter.CallCounted; -import org.taverna.server.port_description.OutputDescription; - -/** - * The core implementation of the web application. - * - * @author Donal Fellows - */ -@Path("/") -@DeclareRoles({ USER, ADMIN }) -@WebService(endpointInterface = "org.taverna.server.master.soap.TavernaServerSOAP", serviceName = "TavernaServer", targetNamespace = SERVER_SOAP) -@WSDLDocumentation("An instance of Taverna " + Version.JAVA + " Server.") -public abstract class TavernaServer implements TavernaServerSOAP, - TavernaServerREST, TavernaServerBean { - /** - * The root of descriptions of the server in JMX. - */ - public static final String JMX_ROOT = "Taverna:group=Server-" - + Version.JAVA + ",name="; - - /** The logger for the server framework. */ - public Log log = getLog("Taverna.Server.Webapp"); - - @PreDestroy - void closeLog() { - log = null; - } - - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // CONNECTIONS TO JMX, SPRING AND CXF - - @Resource - WebServiceContext jaxws; - @Context - private HttpHeaders jaxrsHeaders; - - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // STATE VARIABLES AND SPRING SETTERS - - /** - * For building descriptions of the expected inputs and actual outputs of a - * workflow. - */ - private ContentsDescriptorBuilder cdBuilder; - /** - * Utilities for accessing files on the local-worker. - */ - private FilenameUtils fileUtils; - /** How notifications are dispatched. */ - private NotificationEngine notificationEngine; - /** Main support class. */ - private TavernaServerSupport support; - /** A storage facility for workflow runs. */ - private RunStore runStore; - /** Encapsulates the policies applied by this server. */ - private Policy policy; - /** Where Atom events come from. */ - EventDAO eventSource; - /** Reference to the main interaction feed. */ - private String interactionFeed; - - @Override - @Required - public void setFileUtils(FilenameUtils converter) { - this.fileUtils = converter; - } - - @Override - @Required - public void setContentsDescriptorBuilder(ContentsDescriptorBuilder cdBuilder) { - this.cdBuilder = cdBuilder; - } - - @Override - @Required - public void setNotificationEngine(NotificationEngine notificationEngine) { - this.notificationEngine = notificationEngine; - } - - /** - * @param support - * the support to set - */ - @Override - @Required - public void setSupport(TavernaServerSupport support) { - this.support = support; - } - - @Override - @Required - public void setRunStore(RunStore runStore) { - this.runStore = runStore; - } - - @Override - @Required - public void setPolicy(Policy policy) { - this.policy = policy; - } - - @Override - @Required - public void setEventSource(EventDAO eventSource) { - this.eventSource = eventSource; - } - - /** - * The location of a service-wide interaction feed, derived from a - * properties file. Expected to be <i>actually</i> not set (to a real - * value). - * - * @param interactionFeed - * The URL, which will be resolved relative to the location of - * the webapp, or the string "<tt>none</tt>" (which corresponds - * to a <tt>null</tt>). - */ - public void setInteractionFeed(String interactionFeed) { - if ("none".equals(interactionFeed)) - interactionFeed = null; - else if (interactionFeed != null && interactionFeed.startsWith("${")) - interactionFeed = null; - this.interactionFeed = interactionFeed; - } - - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // REST INTERFACE - - @Override - @CallCounted - @PerfLogged - public ServerDescription describeService(UriInfo ui) { - jaxrsUriInfo.set(new WeakReference<>(ui)); - return new ServerDescription(ui, resolve(interactionFeed)); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public RunList listUsersRuns(UriInfo ui) { - jaxrsUriInfo.set(new WeakReference<>(ui)); - return new RunList(runs(), secure(ui).path("{name}")); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Response submitWorkflow(Workflow workflow, UriInfo ui) - throws NoUpdateException { - jaxrsUriInfo.set(new WeakReference<>(ui)); - checkCreatePolicy(workflow); - String name = support.buildWorkflow(workflow); - return created(secure(ui).path("{uuid}").build(name)).build(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Response submitWorkflowByURL(List<URI> referenceList, UriInfo ui) - throws NoCreateException { - jaxrsUriInfo.set(new WeakReference<>(ui)); - if (referenceList == null || referenceList.size() == 0) - throw new NoCreateException("no workflow URI supplied"); - URI workflowURI = referenceList.get(0); - checkCreatePolicy(workflowURI); - Workflow workflow; - try { - workflow = support.getWorkflowDocumentFromURI(workflowURI); - } catch (IOException e) { - throw new NoCreateException("could not read workflow", e); - } - String name = support.buildWorkflow(workflow); - return created(secure(ui).path("{uuid}").build(name)).build(); - } - - @Override - @CallCounted - @PerfLogged - public int getServerMaxRuns() { - return support.getMaxSimultaneousRuns(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed({ USER, SELF }) - public TavernaServerRunREST getRunResource(String runName, UriInfo ui) - throws UnknownRunException { - jaxrsUriInfo.set(new WeakReference<>(ui)); - RunREST rr = makeRunInterface(); - rr.setRun(support.getRun(runName)); - rr.setRunName(runName); - return rr; - } - - private ThreadLocal<Reference<UriInfo>> jaxrsUriInfo = new InheritableThreadLocal<>(); - - private UriInfo getUriInfo() { - if (jaxrsUriInfo.get() == null) - return null; - return jaxrsUriInfo.get().get(); - } - - @Override - @CallCounted - public abstract PolicyView getPolicyDescription(); - - @Override - @CallCounted - public Response serviceOptions() { - return opt(); - } - - @Override - @CallCounted - public Response runsOptions() { - return opt("POST"); - } - - /** - * Construct a RESTful interface to a run. - * - * @return The handle to the interface, as decorated by Spring. - */ - protected abstract RunREST makeRunInterface(); - - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // SOAP INTERFACE - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public RunReference[] listRuns() { - ArrayList<RunReference> ws = new ArrayList<>(); - UriBuilder ub = getRunUriBuilder(); - for (String runName : runs().keySet()) - ws.add(new RunReference(runName, ub)); - return ws.toArray(new RunReference[ws.size()]); - } - - private void checkCreatePolicy(Workflow workflow) throws NoCreateException { - List<URI> pwu = policy - .listPermittedWorkflowURIs(support.getPrincipal()); - if (pwu == null || pwu.size() == 0) - return; - throw new NoCreateException("server policy: will only start " - + "workflows sourced from permitted URI list"); - } - - private void checkCreatePolicy(URI workflowURI) throws NoCreateException { - List<URI> pwu = policy - .listPermittedWorkflowURIs(support.getPrincipal()); - if (pwu == null || pwu.size() == 0 || pwu.contains(workflowURI)) - return; - throw new NoCreateException("workflow URI not on permitted list"); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public RunReference submitWorkflow(Workflow workflow) - throws NoUpdateException { - checkCreatePolicy(workflow); - String name = support.buildWorkflow(workflow); - return new RunReference(name, getRunUriBuilder()); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public RunReference submitWorkflowMTOM(WrappedWorkflow workflow) - throws NoUpdateException { - Workflow wf; - try { - wf = workflow.getWorkflow(); - } catch (IOException e) { - throw new NoCreateException(e.getMessage(), e); - } - checkCreatePolicy(wf); - String name = support.buildWorkflow(wf); - return new RunReference(name, getRunUriBuilder()); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public RunReference submitWorkflowByURI(URI workflowURI) - throws NoCreateException { - checkCreatePolicy(workflowURI); - Workflow workflow; - try { - workflow = support.getWorkflowDocumentFromURI(workflowURI); - } catch (IOException e) { - throw new NoCreateException("could not read workflow", e); - } - String name = support.buildWorkflow(workflow); - return new RunReference(name, getRunUriBuilder()); - } - - @Override - @CallCounted - @PerfLogged - public URI[] getServerWorkflows() { - return support.getPermittedWorkflowURIs(); - } - - @Override - @CallCounted - @PerfLogged - public String[] getServerListeners() { - List<String> types = support.getListenerTypes(); - return types.toArray(new String[types.size()]); - } - - @Override - @CallCounted - @PerfLogged - public String[] getServerNotifiers() { - List<String> dispatchers = notificationEngine - .listAvailableDispatchers(); - return dispatchers.toArray(new String[dispatchers.size()]); - } - - @Override - @CallCounted - @PerfLogged - public List<Capability> getServerCapabilities() { - return support.getCapabilities(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void destroyRun(String runName) throws UnknownRunException, - NoUpdateException { - support.unregisterRun(runName, null); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getRunDescriptiveName(String runName) - throws UnknownRunException { - return support.getRun(runName).getName(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunDescriptiveName(String runName, String descriptiveName) - throws UnknownRunException, NoUpdateException { - TavernaRun run = support.getRun(runName); - support.permitUpdate(run); - run.setName(descriptiveName); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Workflow getRunWorkflow(String runName) throws UnknownRunException { - return support.getRun(runName).getWorkflow(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public WrappedWorkflow getRunWorkflowMTOM(String runName) - throws UnknownRunException { - WrappedWorkflow ww = new WrappedWorkflow(); - ww.setWorkflow(support.getRun(runName).getWorkflow()); - return ww; - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public ProfileList getRunWorkflowProfiles(String runName) - throws UnknownRunException { - return support.getProfileDescriptor(support.getRun(runName) - .getWorkflow()); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Date getRunExpiry(String runName) throws UnknownRunException { - return support.getRun(runName).getExpiry(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunExpiry(String runName, Date d) - throws UnknownRunException, NoUpdateException { - support.updateExpiry(support.getRun(runName), d); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Date getRunCreationTime(String runName) throws UnknownRunException { - return support.getRun(runName).getCreationTimestamp(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Date getRunFinishTime(String runName) throws UnknownRunException { - return support.getRun(runName).getFinishTimestamp(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Date getRunStartTime(String runName) throws UnknownRunException { - return support.getRun(runName).getStartTimestamp(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Status getRunStatus(String runName) throws UnknownRunException { - return support.getRun(runName).getStatus(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String setRunStatus(String runName, Status s) - throws UnknownRunException, NoUpdateException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - if (s == Status.Operating && w.getStatus() == Status.Initialized) { - if (!support.getAllowStartWorkflowRuns()) - throw new OverloadedException(); - try { - String issue = w.setStatus(s); - if (issue == null) - return ""; - if (issue.isEmpty()) - return "unknown reason for partial change"; - return issue; - } catch (RuntimeException | NoUpdateException e) { - log.info("failed to start run " + runName, e); - throw e; - } - } else { - w.setStatus(s); - return ""; - } - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getRunStdout(String runName) throws UnknownRunException { - try { - return support.getProperty(runName, "io", "stdout"); - } catch (NoListenerException e) { - return ""; - } - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getRunStderr(String runName) throws UnknownRunException { - try { - return support.getProperty(runName, "io", "stderr"); - } catch (NoListenerException e) { - return ""; - } - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public JobUsageRecord getRunUsageRecord(String runName) - throws UnknownRunException { - try { - String ur = support.getProperty(runName, "io", "usageRecord"); - if (ur.isEmpty()) - return null; - return JobUsageRecord.unmarshal(ur); - } catch (NoListenerException e) { - return null; - } catch (JAXBException e) { - log.info("failed to deserialize non-empty usage record", e); - return null; - } - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getRunLog(String runName) throws UnknownRunException { - try { - return support.getLogs(support.getRun(runName)).get("UTF-8"); - } catch (UnsupportedEncodingException e) { - log.warn("unexpected encoding problem", e); - return ""; - } - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public FileContents getRunBundle(String runName) - throws UnknownRunException, FilesystemAccessException, - NoDirectoryEntryException { - File f = fileUtils.getFile(support.getRun(runName), PROV_BUNDLE); - FileContents fc = new FileContents(); - // We *know* the content type, by definition - fc.setFile(f, "application/vnd.wf4ever.robundle+zip"); - return fc; - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public boolean getRunGenerateProvenance(String runName) - throws UnknownRunException { - return support.getRun(runName).getGenerateProvenance(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunGenerateProvenance(String runName, boolean generate) - throws UnknownRunException, NoUpdateException { - TavernaRun run = support.getRun(runName); - support.permitUpdate(run); - run.setGenerateProvenance(generate); - } - - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // SOAP INTERFACE - Security - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getRunOwner(String runName) throws UnknownRunException { - return support.getRun(runName).getSecurityContext().getOwner() - .getName(); - } - - /** - * Look up a security context, applying access control rules for access to - * the parts of the context that are only open to the owner. - * - * @param runName - * The name of the workflow run. - * @param initialOnly - * Whether to check if we're in the initial state. - * @return The security context. Never <tt>null</tt>. - * @throws UnknownRunException - * @throws NotOwnerException - * @throws BadStateChangeException - */ - private TavernaSecurityContext getRunSecurityContext(String runName, - boolean initialOnly) throws UnknownRunException, NotOwnerException, - BadStateChangeException { - TavernaRun run = support.getRun(runName); - TavernaSecurityContext c = run.getSecurityContext(); - if (!c.getOwner().equals(support.getPrincipal())) - throw new NotOwnerException(); - if (initialOnly && run.getStatus() != Initialized) - throw new BadStateChangeException(); - return c; - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Credential[] getRunCredentials(String runName) - throws UnknownRunException, NotOwnerException { - try { - return getRunSecurityContext(runName, false).getCredentials(); - } catch (BadStateChangeException e) { - Error e2 = new Error("impossible"); - e2.initCause(e); - throw e2; - } - } - - private Credential findCredential(TavernaSecurityContext c, String id) - throws NoCredentialException { - for (Credential t : c.getCredentials()) - if (t.id.equals(id)) - return t; - throw new NoCredentialException(); - } - - private Trust findTrust(TavernaSecurityContext c, String id) - throws NoCredentialException { - for (Trust t : c.getTrusted()) - if (t.id.equals(id)) - return t; - throw new NoCredentialException(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String setRunCredential(String runName, String credentialID, - Credential credential) throws UnknownRunException, - NotOwnerException, InvalidCredentialException, - NoCredentialException, BadStateChangeException { - TavernaSecurityContext c = getRunSecurityContext(runName, true); - if (credentialID == null || credentialID.isEmpty()) { - credential.id = randomUUID().toString(); - } else { - credential.id = findCredential(c, credentialID).id; - } - URI uri = getRunUriBuilder().path("security/credentials/{credid}") - .build(runName, credential.id); - credential.href = uri.toString(); - c.validateCredential(credential); - c.addCredential(credential); - return credential.id; - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void deleteRunCredential(String runName, String credentialID) - throws UnknownRunException, NotOwnerException, - NoCredentialException, BadStateChangeException { - getRunSecurityContext(runName, true).deleteCredential( - new Credential.Dummy(credentialID)); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Trust[] getRunCertificates(String runName) - throws UnknownRunException, NotOwnerException { - try { - return getRunSecurityContext(runName, false).getTrusted(); - } catch (BadStateChangeException e) { - Error e2 = new Error("impossible"); - e2.initCause(e); - throw e2; - } - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String setRunCertificates(String runName, String certificateID, - Trust certificate) throws UnknownRunException, NotOwnerException, - InvalidCredentialException, NoCredentialException, - BadStateChangeException { - TavernaSecurityContext c = getRunSecurityContext(runName, true); - if (certificateID == null || certificateID.isEmpty()) { - certificate.id = randomUUID().toString(); - } else { - certificate.id = findTrust(c, certificateID).id; - } - URI uri = getRunUriBuilder().path("security/trusts/{certid}").build( - runName, certificate.id); - certificate.href = uri.toString(); - c.validateTrusted(certificate); - c.addTrusted(certificate); - return certificate.id; - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void deleteRunCertificates(String runName, String certificateID) - throws UnknownRunException, NotOwnerException, - NoCredentialException, BadStateChangeException { - TavernaSecurityContext c = getRunSecurityContext(runName, true); - Trust toDelete = new Trust(); - toDelete.id = certificateID; - c.deleteTrusted(toDelete); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public PermissionList listRunPermissions(String runName) - throws UnknownRunException, NotOwnerException { - PermissionList pl = new PermissionList(); - pl.permission = new ArrayList<>(); - Map<String, Permission> perm; - try { - perm = support.getPermissionMap(getRunSecurityContext(runName, - false)); - } catch (BadStateChangeException e) { - log.error("unexpected error from internal API", e); - perm = emptyMap(); - } - List<String> users = new ArrayList<>(perm.keySet()); - sort(users); - for (String user : users) - pl.permission.add(new PermissionList.SinglePermissionMapping(user, - perm.get(user))); - return pl; - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunPermission(String runName, String userName, - Permission permission) throws UnknownRunException, - NotOwnerException { - try { - support.setPermission(getRunSecurityContext(runName, false), - userName, permission); - } catch (BadStateChangeException e) { - log.error("unexpected error from internal API", e); - } - } - - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // SOAP INTERFACE - Filesystem connection - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public OutputDescription getRunOutputDescription(String runName) - throws UnknownRunException, BadStateChangeException, - FilesystemAccessException, NoDirectoryEntryException { - TavernaRun run = support.getRun(runName); - if (run.getStatus() == Initialized) - throw new BadStateChangeException( - "may not get output description in initial state"); - return cdBuilder.makeOutputDescriptor(run, null); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public DirEntry[] getRunDirectoryContents(String runName, DirEntry d) - throws UnknownRunException, FilesystemAccessException, - NoDirectoryEntryException { - List<DirEntry> result = new ArrayList<>(); - for (DirectoryEntry e : fileUtils.getDirectory(support.getRun(runName), - convert(d)).getContents()) - result.add(convert(newInstance(null, e))); - return result.toArray(new DirEntry[result.size()]); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public byte[] getRunDirectoryAsZip(String runName, DirEntry d) - throws UnknownRunException, FilesystemAccessException, - NoDirectoryEntryException { - try { - return toByteArray(fileUtils.getDirectory(support.getRun(runName), - convert(d)).getContentsAsZip()); - } catch (IOException e) { - throw new FilesystemAccessException("problem serializing ZIP data", - e); - } - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public ZippedDirectory getRunDirectoryAsZipMTOM(String runName, DirEntry d) - throws UnknownRunException, FilesystemAccessException, - NoDirectoryEntryException { - return new ZippedDirectory(fileUtils.getDirectory( - support.getRun(runName), convert(d))); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public DirEntry makeRunDirectory(String runName, DirEntry parent, - String name) throws UnknownRunException, NoUpdateException, - FilesystemAccessException, NoDirectoryEntryException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - Directory dir = fileUtils.getDirectory(w, convert(parent)) - .makeSubdirectory(support.getPrincipal(), name); - return convert(newInstance(null, dir)); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public DirEntry makeRunFile(String runName, DirEntry parent, String name) - throws UnknownRunException, NoUpdateException, - FilesystemAccessException, NoDirectoryEntryException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - File f = fileUtils.getDirectory(w, convert(parent)).makeEmptyFile( - support.getPrincipal(), name); - return convert(newInstance(null, f)); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void destroyRunDirectoryEntry(String runName, DirEntry d) - throws UnknownRunException, NoUpdateException, - FilesystemAccessException, NoDirectoryEntryException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - fileUtils.getDirEntry(w, convert(d)).destroy(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public byte[] getRunFileContents(String runName, DirEntry d) - throws UnknownRunException, FilesystemAccessException, - NoDirectoryEntryException { - File f = fileUtils.getFile(support.getRun(runName), convert(d)); - return f.getContents(0, -1); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunFileContents(String runName, DirEntry d, - byte[] newContents) throws UnknownRunException, NoUpdateException, - FilesystemAccessException, NoDirectoryEntryException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - fileUtils.getFile(w, convert(d)).setContents(newContents); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public FileContents getRunFileContentsMTOM(String runName, DirEntry d) - throws UnknownRunException, FilesystemAccessException, - NoDirectoryEntryException { - File f = fileUtils.getFile(support.getRun(runName), convert(d)); - FileContents fc = new FileContents(); - fc.setFile(f, support.getEstimatedContentType(f)); - return fc; - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunFileContentsFromURI(String runName, - DirEntryReference file, URI reference) - throws UnknownRunException, NoUpdateException, - FilesystemAccessException, NoDirectoryEntryException { - TavernaRun run = support.getRun(runName); - support.permitUpdate(run); - File f = fileUtils.getFile(run, file); - try { - support.copyDataToFile(reference, f); - } catch (IOException e) { - throw new FilesystemAccessException( - "problem transferring data from URI", e); - } - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunFileContentsMTOM(String runName, FileContents newContents) - throws UnknownRunException, NoUpdateException, - FilesystemAccessException, NoDirectoryEntryException { - TavernaRun run = support.getRun(runName); - support.permitUpdate(run); - File f = fileUtils.getFile(run, newContents.name); - f.setContents(new byte[0]); - support.copyDataToFile(newContents.fileData, f); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getRunFileType(String runName, DirEntry d) - throws UnknownRunException, FilesystemAccessException, - NoDirectoryEntryException { - return support.getEstimatedContentType(fileUtils.getFile( - support.getRun(runName), convert(d))); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public long getRunFileLength(String runName, DirEntry d) - throws UnknownRunException, FilesystemAccessException, - NoDirectoryEntryException { - return fileUtils.getFile(support.getRun(runName), convert(d)).getSize(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public Date getRunFileModified(String runName, DirEntry d) - throws UnknownRunException, FilesystemAccessException, - NoDirectoryEntryException { - return fileUtils.getFile(support.getRun(runName), convert(d)) - .getModificationDate(); - } - - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // SOAP INTERFACE - Run listeners - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String[] getRunListeners(String runName) throws UnknownRunException { - TavernaRun w = support.getRun(runName); - List<String> result = new ArrayList<>(); - for (Listener l : w.getListeners()) - result.add(l.getName()); - return result.toArray(new String[result.size()]); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String addRunListener(String runName, String listenerType, - String configuration) throws UnknownRunException, - NoUpdateException, NoListenerException { - return support.makeListener(support.getRun(runName), listenerType, - configuration).getName(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getRunListenerConfiguration(String runName, - String listenerName) throws UnknownRunException, - NoListenerException { - return support.getListener(runName, listenerName).getConfiguration(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String[] getRunListenerProperties(String runName, String listenerName) - throws UnknownRunException, NoListenerException { - return support.getListener(runName, listenerName).listProperties() - .clone(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getRunListenerProperty(String runName, String listenerName, - String propName) throws UnknownRunException, NoListenerException { - return support.getListener(runName, listenerName).getProperty(propName); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunListenerProperty(String runName, String listenerName, - String propName, String value) throws UnknownRunException, - NoUpdateException, NoListenerException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - Listener l = support.getListener(w, listenerName); - try { - l.getProperty(propName); // sanity check! - l.setProperty(propName, value); - } catch (RuntimeException e) { - throw new NoListenerException("problem setting property: " - + e.getMessage(), e); - } - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public InputDescription getRunInputs(String runName) - throws UnknownRunException { - return new InputDescription(support.getRun(runName)); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getRunOutputBaclavaFile(String runName) - throws UnknownRunException { - return support.getRun(runName).getOutputBaclavaFile(); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunInputBaclavaFile(String runName, String fileName) - throws UnknownRunException, NoUpdateException, - FilesystemAccessException, BadStateChangeException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - w.setInputBaclavaFile(fileName); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunInputPortFile(String runName, String portName, - String portFilename) throws UnknownRunException, NoUpdateException, - FilesystemAccessException, BadStateChangeException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - Input i = support.getInput(w, portName); - if (i == null) - i = w.makeInput(portName); - i.setFile(portFilename); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunInputPortValue(String runName, String portName, - String portValue) throws UnknownRunException, NoUpdateException, - BadStateChangeException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - Input i = support.getInput(w, portName); - if (i == null) - i = w.makeInput(portName); - i.setValue(portValue); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunInputPortListDelimiter(String runName, String portName, - String delimiter) throws UnknownRunException, NoUpdateException, - BadStateChangeException, BadPropertyValueException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - Input i = support.getInput(w, portName); - if (i == null) - i = w.makeInput(portName); - if (delimiter != null && delimiter.isEmpty()) - delimiter = null; - if (delimiter != null) { - if (delimiter.length() > 1) - throw new BadPropertyValueException("delimiter too long"); - if (delimiter.charAt(0) < 1 || delimiter.charAt(0) > 127) - throw new BadPropertyValueException( - "delimiter character must be non-NUL ASCII"); - } - i.setDelimiter(delimiter); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public void setRunOutputBaclavaFile(String runName, String outputFile) - throws UnknownRunException, NoUpdateException, - FilesystemAccessException, BadStateChangeException { - TavernaRun w = support.getRun(runName); - support.permitUpdate(w); - w.setOutputBaclavaFile(outputFile); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public org.taverna.server.port_description.InputDescription getRunInputDescriptor( - String runName) throws UnknownRunException { - return cdBuilder.makeInputDescriptor(support.getRun(runName), null); - } - - @Override - @CallCounted - @PerfLogged - @RolesAllowed(USER) - public String getServerStatus() { - return support.getAllowNewWorkflowRuns() ? "operational" : "suspended"; - } - - // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - // SUPPORT METHODS - - @Override - public boolean initObsoleteSOAPSecurity(TavernaSecurityContext c) { - try { - javax.xml.ws.handler.MessageContext msgCtxt = (jaxws == null ? null - : jaxws.getMessageContext()); - if (msgCtxt == null) - return true; - c.initializeSecurityFromSOAPContext(msgCtxt); - return false; - } catch (IllegalStateException e) { - /* ignore; not much we can do */ - return true; - } - } - - @Override - public boolean initObsoleteRESTSecurity(TavernaSecurityContext c) { - if (jaxrsHeaders == null) - return true; - c.initializeSecurityFromRESTContext(jaxrsHeaders); - return false; - } - - /** - * A creator of substitute {@link URI} builders. - * - * @return A URI builder configured so that it takes a path parameter that - * corresponds to the run ID (but with no such ID applied). - */ - UriBuilder getRunUriBuilder() { - return getBaseUriBuilder().path("runs/{uuid}"); - } - - @Override - public UriBuilder getRunUriBuilder(TavernaRun run) { - return fromUri(getRunUriBuilder().build(run.getId())); - } - - private final String DEFAULT_HOST = "localhost:8080"; // Crappy default - - private String getHostLocation() { - @java.lang.SuppressWarnings("unchecked") - Map<String, List<String>> headers = (Map<String, List<String>>) jaxws - .getMessageContext().get(HTTP_REQUEST_HEADERS); - if (headers != null) { - List<String> host = headers.get("HOST"); - if (host != null && !host.isEmpty()) - return host.get(0); - } - return DEFAULT_HOST; - } - - @Nonnull - private URI getPossiblyInsecureBaseUri() { - // See if JAX-RS can supply the info - UriInfo ui = getUriInfo(); - if (ui != null && ui.getBaseUri() != null) - return ui.getBaseUri(); - // See if JAX-WS *cannot* supply the info - if (jaxws == null || jaxws.getMessageContext() == null) - // Hack to make the test suite work - return URI.create("http://" + DEFAULT_HOST - + "/taverna-server/rest/"); - String pathInfo = (String) jaxws.getMessageContext().get(PATH_INFO); - pathInfo = pathInfo.replaceFirst("/soap$", "/rest/"); - pathInfo = pathInfo.replaceFirst("/rest/.+$", "/rest/"); - return URI.create("http://" + getHostLocation() + pathInfo); - } - - @Override - public UriBuilder getBaseUriBuilder() { - return secure(fromUri(getPossiblyInsecureBaseUri())); - } - - @Override - @Nullable - public String resolve(@Nullable String uri) { - if (uri == null) - return null; - return secure(getPossiblyInsecureBaseUri(), uri).toString(); - } - - private Map<String, TavernaRun> runs() { - return runStore.listRuns(support.getPrincipal(), policy); - } -} - -/** - * RESTful interface to the policies of a Taverna Server installation. - * - * @author Donal Fellows - */ -class PolicyREST implements PolicyView, SupportAware { - private TavernaServerSupport support; - private Policy policy; - private ListenerFactory listenerFactory; - private NotificationEngine notificationEngine; - - @Override - public void setSupport(TavernaServerSupport support) { - this.support = support; - } - - @Required - public void setPolicy(Policy policy) { - this.policy = policy; - } - - @Required - public void setListenerFactory(ListenerFactory listenerFactory) { - this.listenerFactory = listenerFactory; - } - - @Required - public void setNotificationEngine(NotificationEngine notificationEngine) { - this.notificationEngine = notificationEngine; - } - - @Override - @CallCounted - @PerfLogged - public PolicyDescription getDescription(UriInfo ui) { - return new PolicyDescription(ui); - } - - @Override - @CallCounted - @PerfLogged - public int getMaxSimultaneousRuns() { - Integer limit = policy.getMaxRuns(support.getPrincipal()); - if (limit == null) - return policy.getMaxRuns(); - return min(limit.intValue(), policy.getMaxRuns()); - } - - @Override - @CallCounted - @PerfLogged - public PermittedListeners getPermittedListeners() { - return new PermittedListeners( - listenerFactory.getSupportedListenerTypes()); - } - - @Override - @CallCounted - @PerfLogged - public PermittedWorkflows getPermittedWorkflows() { - return new PermittedWorkflows(policy.listPermittedWorkflowURIs(support - .getPrincipal())); - } - - @Override - @CallCounted - @PerfLogged - public EnabledNotificationFabrics getEnabledNotifiers() { - return new EnabledNotificationFabrics( - notificationEngine.listAvailableDispatchers()); - } - - @Override - @CallCounted - @PerfLogged - public int getMaxOperatingRuns() { - return policy.getOperatingLimit(); - } - - @Override - @CallCounted - @PerfLogged - public CapabilityList getCapabilities() { - CapabilityList cl = new CapabilityList(); - cl.capability.addAll(support.getCapabilities()); - return cl; - } -}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java ---------------------------------------------------------------------- diff --git a/server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java b/server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java deleted file mode 100644 index ce36bd3..0000000 --- a/server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java +++ /dev/null @@ -1,957 +0,0 @@ -/* - * Copyright (C) 2010-2011 The University of Manchester - * - * See the file "LICENSE" for license terms. - */ -package org.taverna.server.master; - -import static eu.medsea.util.MimeUtil.UNKNOWN_MIME_TYPE; -import static eu.medsea.util.MimeUtil.getExtensionMimeTypes; -import static eu.medsea.util.MimeUtil.getMimeType; -import static java.lang.Math.min; -import static org.apache.commons.logging.LogFactory.getLog; -import static org.springframework.jmx.support.MetricType.COUNTER; -import static org.springframework.jmx.support.MetricType.GAUGE; -import static org.taverna.server.master.TavernaServer.JMX_ROOT; -import static org.taverna.server.master.common.Roles.ADMIN; -import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.activation.DataHandler; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.annotation.PreDestroy; -import javax.ws.rs.WebApplicationException; -import javax.xml.bind.JAXBException; - -import org.apache.commons.logging.Log; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Required; -import org.springframework.jmx.export.annotation.ManagedAttribute; -import org.springframework.jmx.export.annotation.ManagedMetric; -import org.springframework.jmx.export.annotation.ManagedResource; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.taverna.server.master.api.ManagementModel; -import org.taverna.server.master.api.TavernaServerBean; -import org.taverna.server.master.common.Capability; -import org.taverna.server.master.common.Permission; -import org.taverna.server.master.common.ProfileList; -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.FilesystemAccessException; -import org.taverna.server.master.exceptions.NoCreateException; -import org.taverna.server.master.exceptions.NoDestroyException; -import org.taverna.server.master.exceptions.NoDirectoryEntryException; -import org.taverna.server.master.exceptions.NoListenerException; -import org.taverna.server.master.exceptions.NoUpdateException; -import org.taverna.server.master.exceptions.UnknownRunException; -import org.taverna.server.master.factories.ListenerFactory; -import org.taverna.server.master.factories.RunFactory; -import org.taverna.server.master.identity.WorkflowInternalAuthProvider.WorkflowSelfAuthority; -import org.taverna.server.master.interfaces.File; -import org.taverna.server.master.interfaces.Input; -import org.taverna.server.master.interfaces.Listener; -import org.taverna.server.master.interfaces.LocalIdentityMapper; -import org.taverna.server.master.interfaces.Policy; -import org.taverna.server.master.interfaces.RunStore; -import org.taverna.server.master.interfaces.TavernaRun; -import org.taverna.server.master.interfaces.TavernaSecurityContext; -import org.taverna.server.master.rest.handler.T2FlowDocumentHandler; -import org.taverna.server.master.utils.CapabilityLister; -import org.taverna.server.master.utils.FilenameUtils; -import org.taverna.server.master.utils.InvocationCounter; -import org.taverna.server.master.utils.UsernamePrincipal; - -import uk.org.taverna.scufl2.api.profiles.Profile; - -/** - * Web application support utilities. - * - * @author Donal Fellows - */ -@ManagedResource(objectName = JMX_ROOT + "Webapp", description = "The main Taverna Server " - + Version.JAVA + " web-application interface.") -public class TavernaServerSupport { - /** The main webapp log. */ - private Log log = getLog("Taverna.Server.Webapp"); - private Log accessLog = getLog("Taverna.Server.Webapp.Access");; - /** Bean used to log counts of external calls. */ - private InvocationCounter counter; - /** A storage facility for workflow runs. */ - private RunStore runStore; - /** Encapsulates the policies applied by this server. */ - private Policy policy; - /** Connection to the persistent state of this service. */ - private ManagementModel stateModel; - /** A factory for event listeners to attach to workflow runs. */ - private ListenerFactory listenerFactory; - /** A factory for workflow runs. */ - private RunFactory runFactory; - /** How to map the user ID to who to run as. */ - private LocalIdentityMapper idMapper; - /** The code that is coupled to CXF. */ - private TavernaServerBean webapp; - /** How to handle files. */ - private FilenameUtils fileUtils; - /** How to get the server capabilities. */ - private CapabilityLister capabilitySource; - /** - * Whether to log failures during principal retrieval. Should be normally on - * as it indicates a serious problem, but can be switched off for testing. - */ - private boolean logGetPrincipalFailures = true; - private Map<String, String> contentTypeMap; - /** Number of bytes to read when guessing the MIME type. */ - private static final int SAMPLE_SIZE = 1024; - /** Number of bytes to ask for when copying a stream to a file. */ - private static final int TRANSFER_SIZE = 32768; - - @PreDestroy - void closeLog() { - log = null; - } - - /** - * @return Count of the number of external calls into this webapp. - */ - @ManagedMetric(description = "Count of the number of external calls into this webapp.", metricType = COUNTER, category = "throughput") - public int getInvocationCount() { - return counter.getCount(); - } - - /** - * @return Current number of runs. - */ - @ManagedMetric(description = "Current number of runs.", metricType = GAUGE, category = "utilization") - public int getCurrentRunCount() { - return runStore.listRuns(null, policy).size(); - } - - /** - * @return Whether to write submitted workflows to the log. - */ - @ManagedAttribute(description = "Whether to write submitted workflows to the log.") - public boolean getLogIncomingWorkflows() { - return stateModel.getLogIncomingWorkflows(); - } - - /** - * @param logIncomingWorkflows - * Whether to write submitted workflows to the log. - */ - @ManagedAttribute(description = "Whether to write submitted workflows to the log.") - public void setLogIncomingWorkflows(boolean logIncomingWorkflows) { - stateModel.setLogIncomingWorkflows(logIncomingWorkflows); - } - - /** - * @return Whether outgoing exceptions should be logged before being - * converted to responses. - */ - @ManagedAttribute(description = "Whether outgoing exceptions should be logged before being converted to responses.") - public boolean getLogOutgoingExceptions() { - return stateModel.getLogOutgoingExceptions(); - } - - /** - * @param logOutgoing - * Whether outgoing exceptions should be logged before being - * converted to responses. - */ - @ManagedAttribute(description = "Whether outgoing exceptions should be logged before being converted to responses.") - public void setLogOutgoingExceptions(boolean logOutgoing) { - stateModel.setLogOutgoingExceptions(logOutgoing); - } - - /** - * @return Whether to permit any new workflow runs to be created. - */ - @ManagedAttribute(description = "Whether to permit any new workflow runs to be created; has no effect on existing runs.") - public boolean getAllowNewWorkflowRuns() { - return stateModel.getAllowNewWorkflowRuns(); - } - - /** - * @param allowNewWorkflowRuns - * Whether to permit any new workflow runs to be created. - */ - @ManagedAttribute(description = "Whether to permit any new workflow runs to be created; has no effect on existing runs.") - public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) { - stateModel.setAllowNewWorkflowRuns(allowNewWorkflowRuns); - } - - /** - * @return The server's version identifier. - */ - @ManagedAttribute(description = "The installed version of the server.") - public String getServerVersion() { - return VersionedElement.VERSION + " " + VersionedElement.REVISION + " " - + VersionedElement.TIMESTAMP; - } - - @ManagedAttribute(description = "The URIs of the workfows that this server will allow to be instantiated.") - public URI[] getPermittedWorkflowURIs() { - List<URI> pw = policy.listPermittedWorkflowURIs(null); - if (pw == null) - return new URI[0]; - return pw.toArray(new URI[pw.size()]); - } - - @ManagedAttribute(description = "The URIs of the workfows that this server will allow to be instantiated.") - public void setPermittedWorkflowURIs(URI[] pw) { - if (pw == null) - policy.setPermittedWorkflowURIs(null, new ArrayList<URI>()); - else - policy.setPermittedWorkflowURIs(null, Arrays.asList(pw)); - } - - public int getMaxSimultaneousRuns() { - Integer limit = policy.getMaxRuns(getPrincipal()); - if (limit == null) - return policy.getMaxRuns(); - return min(limit.intValue(), policy.getMaxRuns()); - } - - @Autowired - private T2FlowDocumentHandler t2flowHandler; - - public Workflow getWorkflowDocumentFromURI(URI uri) - throws WebApplicationException, IOException { - URLConnection conn = uri.toURL().openConnection(); - conn.setRequestProperty("Accept", T2FLOW); - conn.connect(); - // Tricky point: we know the reader part of the handler only cares - // about the stream argument. - return t2flowHandler.readFrom(null, null, null, null, null, - conn.getInputStream()); - } - - public List<String> getListenerTypes() { - return listenerFactory.getSupportedListenerTypes(); - } - - /** - * @param policy - * The policy being installed by Spring. - */ - @Required - public void setPolicy(Policy policy) { - this.policy = policy; - } - - /** - * @param listenerFactory - * The listener factory being installed by Spring. - */ - @Required - public void setListenerFactory(ListenerFactory listenerFactory) { - this.listenerFactory = listenerFactory; - } - - /** - * @param runFactory - * The run factory being installed by Spring. - */ - @Required - public void setRunFactory(RunFactory runFactory) { - this.runFactory = runFactory; - } - - /** - * @param runStore - * The run store being installed by Spring. - */ - @Required - public void setRunStore(RunStore runStore) { - this.runStore = runStore; - } - - /** - * @param stateModel - * The state model engine being installed by Spring. - */ - @Required - public void setStateModel(ManagementModel stateModel) { - this.stateModel = stateModel; - } - - /** - * @param mapper - * The identity mapper being installed by Spring. - */ - @Required - public void setIdMapper(LocalIdentityMapper mapper) { - this.idMapper = mapper; - } - - /** - * @param counter - * The object whose job it is to manage the counting of - * invocations. Installed by Spring. - */ - @Required - public void setInvocationCounter(InvocationCounter counter) { - this.counter = counter; - } - - /** - * @param webapp - * The web-app being installed by Spring. - */ - @Required - public void setWebapp(TavernaServerBean webapp) { - this.webapp = webapp; - } - - /** - * @param fileUtils - * The file handling utilities. - */ - @Required - public void setFileUtils(FilenameUtils fileUtils) { - this.fileUtils = fileUtils; - } - - /** - * @param logthem - * Whether to log failures relating to principals. - */ - public void setLogGetPrincipalFailures(boolean logthem) { - logGetPrincipalFailures = logthem; - } - - public Map<String, String> getContentTypeMap() { - return contentTypeMap; - } - - /** - * Mapping from filename suffixes (e.g., "baclava") to content types. - * - * @param contentTypeMap - * The mapping to install. - */ - @Required - public void setContentTypeMap(Map<String, String> contentTypeMap) { - this.contentTypeMap = contentTypeMap; - } - - @Required - public void setCapabilitySource(CapabilityLister capabilitySource) { - this.capabilitySource = capabilitySource; - } - - /** - * Test whether the current user can do updates to the given run. - * - * @param run - * The workflow run to do the test on. - * @throws NoUpdateException - * If the current user is not permitted to update the run. - */ - public void permitUpdate(@Nonnull TavernaRun run) throws NoUpdateException { - if (isSuperUser()) { - accessLog - .warn("check for admin powers passed; elevated access rights granted for update"); - return; // Superusers are fully authorized to access others things - } - if (getSelfAuthority() != null) { - // At this point, must already be accessing self as that is checked - // in getRun(). - return; - } - policy.permitUpdate(getPrincipal(), run); - } - - /** - * Test whether the current user can destroy or control the lifespan of the - * given run. - * - * @param run - * The workflow run to do the test on. - * @throws NoDestroyException - * If the current user is not permitted to destroy the run. - */ - public void permitDestroy(TavernaRun run) throws NoDestroyException { - if (isSuperUser()) { - accessLog - .warn("check for admin powers passed; elevated access rights granted for destroy"); - return; // Superusers are fully authorized to access others things - } - if (getSelfAuthority() != null) - throw new NoDestroyException(); - policy.permitDestroy(getPrincipal(), run); - } - - /** - * Gets the identity of the user currently accessing the webapp, which is - * stored in a thread-safe way in the webapp's container's context. - * - * @return The identity of the user accessing the webapp. - */ - @Nonnull - public UsernamePrincipal getPrincipal() { - try { - Authentication auth = SecurityContextHolder.getContext() - .getAuthentication(); - if (auth == null || !auth.isAuthenticated()) { - if (logGetPrincipalFailures) - log.warn("failed to get auth; going with <NOBODY>"); - return new UsernamePrincipal("<NOBODY>"); - } - return new UsernamePrincipal(auth); - } catch (RuntimeException e) { - if (logGetPrincipalFailures) - log.info("failed to map principal", e); - throw e; - } - } - - private WorkflowSelfAuthority getSelfAuthority() { - try { - Authentication a = SecurityContextHolder.getContext() - .getAuthentication(); - for (GrantedAuthority ga : a.getAuthorities()) - if (ga instanceof WorkflowSelfAuthority) - return (WorkflowSelfAuthority) ga; - } catch (RuntimeException e) { - } - return null; - } - - /** - * Obtain the workflow run with a particular name. - * - * @param name - * The name of the run to look up. - * @return A workflow run handle that the current user has at least - * permission to read. - * @throws UnknownRunException - * If the workflow run doesn't exist or the current user doesn't - * have permission to see it. - */ - @Nonnull - public TavernaRun getRun(@Nonnull String name) throws UnknownRunException { - if (isSuperUser()) { - accessLog - .info("check for admin powers passed; elevated access rights granted for read"); - return runStore.getRun(name); - } - WorkflowSelfAuthority wsa = getSelfAuthority(); - if (wsa != null) { - if (wsa.getWorkflowID().equals(name)) - return runStore.getRun(name); - throw new UnknownRunException(); - } - return runStore.getRun(getPrincipal(), policy, name); - } - - /** - * Construct a listener attached to the given run. - * - * @param run - * The workflow run to attach the listener to. - * @param type - * The name of the type of run to create. - * @param configuration - * The configuration description to pass into the listener. The - * format of this string is up to the listener to define. - * @return A handle to the listener which can be used to further configure - * any properties. - * @throws NoListenerException - * If the listener type is unrecognized or the configuration is - * invalid. - * @throws NoUpdateException - * If the run does not permit the current user to add listeners - * (or perform other types of update). - */ - @Nonnull - public Listener makeListener(@Nonnull TavernaRun run, @Nonnull String type, - @Nonnull String configuration) throws NoListenerException, - NoUpdateException { - permitUpdate(run); - return listenerFactory.makeListener(run, type, configuration); - } - - /** - * Obtain a listener that is already attached to a workflow run. - * - * @param run - * The workflow run to search. - * @param listenerName - * The name of the listener to look up. - * @return The listener instance interface. - * @throws NoListenerException - * If no listener with that name exists. - */ - @Nonnull - public Listener getListener(TavernaRun run, String listenerName) - throws NoListenerException { - for (Listener l : run.getListeners()) - if (l.getName().equals(listenerName)) - return l; - throw new NoListenerException(); - } - - /** - * Obtain a property from a listener that is already attached to a workflow - * run. - * - * @param runName - * The ID of the workflow run to search. - * @param listenerName - * The name of the listener to look up in. - * @param propertyName - * The name of the property to fetch. - * @return The property value. - * @throws NoListenerException - * If no listener with that name exists, or no property with - * that name exists. - * @throws UnknownRunException - * If no run with that name exists. - */ - @Nonnull - public String getProperty(String runName, String listenerName, - String propertyName) throws NoListenerException, - UnknownRunException { - return getListener(runName, listenerName).getProperty(propertyName); - } - - /** - * Obtain a property from a listener that is already attached to a workflow - * run. - * - * @param run - * The workflow run to search. - * @param listenerName - * The name of the listener to look up in. - * @param propertyName - * The name of the property to fetch. - * @return The property value. - * @throws NoListenerException - * If no listener with that name exists, or no property with - * that name exists. - */ - @Nonnull - public String getProperty(TavernaRun run, String listenerName, - String propertyName) throws NoListenerException { - return getListener(run, listenerName).getProperty(propertyName); - } - - /** - * Get the permission description for the given user. - * - * @param context - * A security context associated with a particular workflow run. - * Note that only the owner of a workflow run may get the - * security context in the first place. - * @param userName - * The name of the user to look up the permission for. - * @return A permission description. - */ - @Nonnull - public Permission getPermission(@Nonnull TavernaSecurityContext context, - @Nonnull String userName) { - if (context.getPermittedDestroyers().contains(userName)) - return Permission.Destroy; - if (context.getPermittedUpdaters().contains(userName)) - return Permission.Update; - if (context.getPermittedReaders().contains(userName)) - return Permission.Read; - return Permission.None; - } - - /** - * Set the permissions for the given user. - * - * @param context - * A security context associated with a particular workflow run. - * Note that only the owner of a workflow run may get the - * security context in the first place. - * @param userName - * The name of the user to set the permission for. - * @param permission - * The description of the permission to grant. Note that the - * owner of a workflow run always has the equivalent of - * {@link Permission#Destroy}; this is always enforced before - * checking for other permissions. - */ - public void setPermission(TavernaSecurityContext context, String userName, - Permission permission) { - Set<String> permSet; - boolean doRead = false, doWrite = false, doKill = false; - - switch (permission) { - case Destroy: - doKill = true; - case Update: - doWrite = true; - case Read: - doRead = true; - default: - break; - } - - permSet = context.getPermittedReaders(); - if (doRead) { - if (!permSet.contains(userName)) { - permSet = new HashSet<>(permSet); - permSet.add(userName); - context.setPermittedReaders(permSet); - } - } else if (permSet.contains(userName)) { - permSet = new HashSet<>(permSet); - permSet.remove(userName); - context.setPermittedReaders(permSet); - } - - permSet = context.getPermittedUpdaters(); - if (doWrite) { - if (!permSet.contains(userName)) { - permSet = new HashSet<>(permSet); - permSet.add(userName); - context.setPermittedUpdaters(permSet); - } - } else if (permSet.contains(userName)) { - permSet = new HashSet<>(permSet); - permSet.remove(userName); - context.setPermittedUpdaters(permSet); - } - - permSet = context.getPermittedDestroyers(); - if (doKill) { - if (!permSet.contains(userName)) { - permSet = new HashSet<>(permSet); - permSet.add(userName); - context.setPermittedDestroyers(permSet); - } - } else if (permSet.contains(userName)) { - permSet = new HashSet<>(permSet); - permSet.remove(userName); - context.setPermittedDestroyers(permSet); - } - } - - public Map<String, Permission> getPermissionMap( - TavernaSecurityContext context) { - Map<String, Permission> perm = new HashMap<>(); - for (String u : context.getPermittedReaders()) - perm.put(u, Permission.Read); - for (String u : context.getPermittedUpdaters()) - perm.put(u, Permission.Update); - for (String u : context.getPermittedDestroyers()) - perm.put(u, Permission.Destroy); - return perm; - } - - /** - * Stops a run from being possible to be looked up and destroys it. - * - * @param runName - * The name of the run. - * @param run - * The workflow run. <i>Must</i> correspond to the name. - * @throws NoDestroyException - * If the user is not permitted to destroy the workflow run. - * @throws UnknownRunException - * If the run is unknown (e.g., because it is already - * destroyed). - */ - public void unregisterRun(@Nonnull String runName, @Nonnull TavernaRun run) - throws NoDestroyException, UnknownRunException { - if (run == null) - run = getRun(runName); - permitDestroy(run); - runStore.unregisterRun(runName); - run.destroy(); - } - - /** - * Changes the expiry date of a workflow run. The expiry date is when the - * workflow run becomes eligible for automated destruction. - * - * @param run - * The handle to the workflow run. - * @param date - * When the workflow run should be expired. - * @return When the workflow run will actually be expired. - * @throws NoDestroyException - * If the user is not permitted to destroy the workflow run. - * (Note that lifespan management requires the ability to - * destroy.) - */ - @Nonnull - public Date updateExpiry(@Nonnull TavernaRun run, @Nonnull Date date) - throws NoDestroyException { - permitDestroy(run); - run.setExpiry(date); - return run.getExpiry(); - } - - /** - * Manufacture a workflow run instance. - * - * @param workflow - * The workflow document (t2flow, scufl2?) to instantiate. - * @return The ID of the created workflow run. - * @throws NoCreateException - * If the user is not permitted to create workflows. - */ - public String buildWorkflow(Workflow workflow) throws NoCreateException { - UsernamePrincipal p = getPrincipal(); - if (getSelfAuthority() != null) - throw new NoCreateException( - "runs may not create workflows on their host server"); - if (!stateModel.getAllowNewWorkflowRuns()) - throw new NoCreateException("run creation not currently enabled"); - try { - if (stateModel.getLogIncomingWorkflows()) { - log.info(workflow.marshal()); - } - } catch (JAXBException e) { - log.warn("problem when logging workflow", e); - } - - // Security checks - policy.permitCreate(p, workflow); - if (idMapper != null && idMapper.getUsernameForPrincipal(p) == null) { - log.error("cannot map principal to local user id"); - throw new NoCreateException( - "failed to map security token to local user id"); - } - - TavernaRun run; - try { - run = runFactory.create(p, workflow); - TavernaSecurityContext c = run.getSecurityContext(); - c.initializeSecurityFromContext(SecurityContextHolder.getContext()); - /* - * These next pieces of security initialisation are (hopefully) - * obsolete now that we use Spring Security, but we keep them Just - * In Case. - */ - boolean doRESTinit = webapp.initObsoleteSOAPSecurity(c); - if (doRESTinit) - webapp.initObsoleteRESTSecurity(c); - } catch (Exception e) { - log.error("failed to build workflow run worker", e); - throw new NoCreateException("failed to build workflow run worker"); - } - - return runStore.registerRun(run); - } - - private boolean isSuperUser() { - try { - Authentication auth = SecurityContextHolder.getContext() - .getAuthentication(); - if (auth == null || !auth.isAuthenticated()) - return false; - UserDetails details = (UserDetails) auth.getPrincipal(); - if (log.isDebugEnabled()) - log.debug("checking for admin role for user <" + auth.getName() - + "> in collection " + details.getAuthorities()); - return details.getAuthorities().contains(ADMIN); - } catch (ClassCastException e) { - return false; - } - } - - /** - * Get a particular input to a workflow run. - * - * @param run - * The workflow run to search. - * @param portName - * The name of the input. - * @return The handle of the input, or <tt>null</tt> if no such handle - * exists. - */ - @Nullable - public Input getInput(TavernaRun run, String portName) { - for (Input i : run.getInputs()) - if (i.getName().equals(portName)) - return i; - return null; - } - - /** - * Get a listener attached to a run. - * - * @param runName - * The name of the run to look up - * @param listenerName - * The name of the listener. - * @return The handle of the listener. - * @throws NoListenerException - * If no such listener exists. - * @throws UnknownRunException - * If no such workflow run exists, or if the user does not have - * permission to access it. - */ - public Listener getListener(String runName, String listenerName) - throws NoListenerException, UnknownRunException { - return getListener(getRun(runName), listenerName); - } - - /** - * Given a file, produce a guess at its content type. This uses the content - * type map property, and if that search fails it falls back on the Medsea - * mime type library. - * - * @param f - * The file handle. - * @return The content type. If all else fails, produces good old - * "application/octet-stream". - */ - @Nonnull - public String getEstimatedContentType(@Nonnull File f) { - String name = f.getName(); - for (int idx = name.indexOf('.'); idx != -1; idx = name.indexOf('.', - idx + 1)) { - String mt = contentTypeMap.get(name.substring(idx + 1)); - if (mt != null) - return mt; - } - @Nonnull - String type = getExtensionMimeTypes(name); - if (!type.equals(UNKNOWN_MIME_TYPE)) - return type; - try { - return getMimeType(new ByteArrayInputStream(f.getContents(0, - SAMPLE_SIZE))); - } catch (FilesystemAccessException e) { - return type; - } - } - - public void copyDataToFile(DataHandler handler, File file) - throws FilesystemAccessException { - try { - copyStreamToFile(handler.getInputStream(), file); - } catch (IOException e) { - throw new FilesystemAccessException( - "problem constructing stream from data source", e); - } - } - - public void copyDataToFile(URI uri, File file) - throws MalformedURLException, FilesystemAccessException, - IOException { - copyStreamToFile(uri.toURL().openStream(), file); - } - - public void copyStreamToFile(InputStream stream, File file) - throws FilesystemAccessException { - String name = file.getFullName(); - long total = 0; - try { - byte[] buffer = new byte[TRANSFER_SIZE]; - boolean first = true; - while (true) { - int len = stream.read(buffer); - if (len < 0) - break; - total += len; - if (log.isDebugEnabled()) - log.debug("read " + len - + " bytes from source stream (total: " + total - + ") bound for " + name); - if (len == buffer.length) { - if (first) - file.setContents(buffer); - else - file.appendContents(buffer); - } else { - byte[] newBuf = new byte[len]; - System.arraycopy(buffer, 0, newBuf, 0, len); - if (first) - file.setContents(newBuf); - else - file.appendContents(newBuf); - } - first = false; - } - } catch (IOException exn) { - throw new FilesystemAccessException("failed to transfer bytes", exn); - } - } - - /** - * Build a description of the profiles supported by a workflow. Note that we - * expect the set of profiles to be fairly small. - * - * @param workflow - * The workflow to describe the profiles of. - * @return The descriptor (which might be empty). - */ - public ProfileList getProfileDescriptor(Workflow workflow) { - ProfileList result = new ProfileList(); - String main = workflow.getMainProfileName(); - for (Profile p : workflow.getProfiles()) { - ProfileList.Info i = new ProfileList.Info(); - i.name = p.getName(); - if (main != null && main.equals(i.name)) - i.main = true; - result.profile.add(i); - } - return result; - } - - public boolean getAllowStartWorkflowRuns() { - return runFactory.isAllowingRunsToStart(); - } - - /** - * The list of filenames that logs may occupy. - */ - private static final String[] LOGS = { "logs/detail.log.4", - "logs/detail.log.3", "logs/detail.log.2", "logs/detail.log.1", - "logs/detail.log" }; - - public FileConcatenation getLogs(TavernaRun run) { - FileConcatenation fc = new FileConcatenation(); - for (String name : LOGS) { - try { - fc.add(fileUtils.getFile(run, name)); - } catch (FilesystemAccessException | NoDirectoryEntryException e) { - // Ignore - } - } - return fc; - } - - @Nonnull - public List<Capability> getCapabilities() { - return capabilitySource.getCapabilities(); - } - - static final String PROV_BUNDLE = "out.bundle.zip"; - - public FileConcatenation getProv(TavernaRun run) { - FileConcatenation fc = new FileConcatenation(); - try { - fc.add(fileUtils.getFile(run, PROV_BUNDLE)); - } catch (FilesystemAccessException | NoDirectoryEntryException e) { - // Ignore - } - return fc; - } -}
